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/06/25 23:21:26 UTC

[juneau] branch master updated: Swagger API improvements.

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 854d4c1  Swagger API improvements.
854d4c1 is described below

commit 854d4c13c23011a3333dae35c762d0051a2e0237
Author: JamesBognar <ja...@apache.org>
AuthorDate: Mon Jun 25 19:21:04 2018 -0400

    Swagger API improvements.
---
 .../main/java/org/apache/juneau/config/Config.java |    2 +-
 .../java/org/apache/juneau/config/ConfigMod.java   |    7 +-
 .../apache/juneau/config/event/ConfigEvent.java    |    3 +-
 .../apache/juneau/config/internal/ConfigEntry.java |    2 +-
 .../juneau/config/store/ConfigFileStore.java       |    2 +-
 .../apache/juneau/httppart/UonPartParserTest.java  |    1 +
 .../java/org/apache/juneau/dto/LinkString.java     |    1 +
 .../org/apache/juneau/dto/swagger/Contact.java     |    4 +-
 .../juneau/dto/swagger/ExternalDocumentation.java  |    2 +-
 .../java/org/apache/juneau/dto/swagger/Info.java   |    8 +-
 .../org/apache/juneau/dto/swagger/License.java     |    2 +-
 .../org/apache/juneau/dto/swagger/Operation.java   |    4 +-
 .../src/main/java/org/apache/juneau/BeanMeta.java  |    2 +-
 .../main/java/org/apache/juneau/BeanSession.java   |    2 +
 .../main/java/org/apache/juneau/ObjectList.java    |    5 +-
 .../src/main/java/org/apache/juneau/ObjectMap.java |   53 +-
 .../org/apache/juneau/httppart/HttpPartParser.java |    9 +-
 .../org/apache/juneau/httppart/HttpPartSchema.java | 1316 ++++++++++++++++++++
 .../apache/juneau/httppart/HttpPartSerializer.java |   13 +-
 .../org/apache/juneau/httppart/HttpPartType.java   |    5 +-
 .../apache/juneau/httppart/SimplePartParser.java   |    2 +-
 .../juneau/httppart/SimplePartSerializer.java      |    2 +-
 .../juneau/httppart/oapi/OapiPartParser.java       |  247 ++++
 .../OapiPartParserBuilder.java}                    |  182 +--
 .../OapiPartSerializer.java}                       |   69 +-
 .../OapiPartSerializerBuilder.java}                |  226 ++--
 .../{ => uon}/SimpleUonPartSerializer.java         |    2 +-
 .../{ => uon}/SimpleUonPartSerializerBuilder.java  |    2 +-
 .../juneau/httppart/{ => uon}/UonPartParser.java   |   19 +-
 .../httppart/{ => uon}/UonPartParserBuilder.java   |    2 +-
 .../httppart/{ => uon}/UonPartSerializer.java      |   16 +-
 .../{ => uon}/UonPartSerializerBuilder.java        |    2 +-
 .../java/org/apache/juneau/internal/DateUtils.java |    4 +-
 .../java/org/apache/juneau/internal/IOUtils.java   |    3 +-
 .../org/apache/juneau/internal/JuneauLogger.java   |    2 +-
 .../org/apache/juneau/internal/StringUtils.java    |   65 +-
 .../org/apache/juneau/internal/VersionRange.java   |    4 +-
 .../org/apache/juneau/json/JsonSerializer.java     |    2 +-
 .../main/java/org/apache/juneau/utils/AList.java   |   13 +
 .../org/apache/juneau/utils/CalendarUtils.java     |    7 +-
 .../java/org/apache/juneau/svl/vars/ArgsVar.java   |    2 +-
 .../examples/rest/petstore/PetStoreResource.java   |   12 +-
 .../apache/juneau/microservice/Microservice.java   |    2 +-
 .../rest/test/client/RequestBeanProxyTest.java     |    5 +-
 .../rest/test/client/ThirdPartyProxyTest.java      |    3 +-
 .../apache/juneau/rest/client/NameValuePairs.java  |   13 +-
 .../org/apache/juneau/rest/client/RestCall.java    |  116 +-
 .../org/apache/juneau/rest/client/RestClient.java  |   23 +-
 .../juneau/rest/client/RestClientBuilder.java      |    1 +
 .../rest/client/SerializedNameValuePair.java       |   15 +-
 .../apache/juneau/rest/BasicRestInfoProvider.java  |    8 +-
 .../java/org/apache/juneau/rest/RequestBody.java   |   54 +-
 .../org/apache/juneau/rest/RequestFormData.java    |  163 ++-
 .../org/apache/juneau/rest/RequestHeaders.java     |   70 +-
 .../org/apache/juneau/rest/RequestPathMatch.java   |   61 +-
 .../java/org/apache/juneau/rest/RequestQuery.java  |  107 +-
 .../java/org/apache/juneau/rest/RestContext.java   |   19 +-
 .../org/apache/juneau/rest/RestContextBuilder.java |   11 +-
 .../org/apache/juneau/rest/RestParamDefaults.java  |  124 +-
 .../java/org/apache/juneau/rest/RestRequest.java   |    9 +
 .../java/org/apache/juneau/rest/RestResponse.java  |    2 +-
 .../org/apache/juneau/rest/annotation/Body.java    |   28 +-
 .../org/apache/juneau/rest/annotation/Contact.java |    4 +-
 .../juneau/rest/annotation/ExternalDocs.java       |    6 +-
 .../apache/juneau/rest/annotation/FormData.java    |  522 ++++----
 .../org/apache/juneau/rest/annotation/Header.java  |  500 ++++----
 .../org/apache/juneau/rest/annotation/Items.java   |   26 +-
 .../org/apache/juneau/rest/annotation/License.java |    4 +-
 .../juneau/rest/annotation/MethodSwagger.java      |   14 +-
 .../org/apache/juneau/rest/annotation/Path.java    |  381 +++---
 .../org/apache/juneau/rest/annotation/Query.java   |  525 ++++----
 .../juneau/rest/annotation/ResourceSwagger.java    |   18 +-
 .../apache/juneau/rest/annotation/Response.java    |   13 +-
 .../juneau/rest/annotation/ResponseHeader.java     |   28 +-
 .../juneau/rest/annotation/ResponseStatus.java     |    3 +-
 .../apache/juneau/rest/annotation/RestMethod.java  |    3 +-
 .../juneau/rest/annotation/RestResource.java       |    1 +
 .../org/apache/juneau/rest/annotation/Schema.java  |   52 +-
 .../rest/annotation/{Items.java => SubItems.java}  |   27 +-
 .../org/apache/juneau/rest/annotation/Tag.java     |   10 +-
 .../java/org/apache/juneau/rest/mock/MockRest.java |   23 +-
 .../juneau/rest/mock/MockServletRequest.java       |    4 +-
 .../apache/juneau/rest/util/AnnotationUtils.java   |  243 ++--
 .../org/apache/juneau/rest/util/RestUtils.java     |   14 -
 .../juneau/rest/BasicRestInfoProviderTest.java     |  219 ----
 .../juneau/rest/annotation/BodyAnnotationTest.java |   58 +-
 .../rest/annotation/FormDataAnnotationTest.java    |  392 +-----
 .../rest/annotation/HeaderAnnotationTest.java      |  340 +----
 .../juneau/rest/annotation/PathAnnotationTest.java |  193 +--
 .../rest/annotation/QueryAnnotationTest.java       |  426 +------
 .../annotation/ResponseHeaderAnnotationTest.java   |   56 +-
 91 files changed, 4205 insertions(+), 3062 deletions(-)

diff --git a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
index 9787f6e..b71364b 100644
--- a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
+++ b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
@@ -1370,7 +1370,7 @@ public final class Config extends Context implements ConfigEventListener, Writab
 	 * @return <jk>true</jk> if this section contains the specified key and the key has a non-blank value.
 	 */
 	public boolean exists(String key) {
-		return ! isEmpty(getString(key, null));
+		return isNotEmpty(getString(key, null));
 	}
 
 	/**
diff --git a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/ConfigMod.java b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/ConfigMod.java
index c592c9d..2da946a 100644
--- a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/ConfigMod.java
+++ b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/ConfigMod.java
@@ -12,9 +12,10 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.config;
 
+import static org.apache.juneau.internal.StringUtils.*;
+
 import java.util.*;
 
-import org.apache.juneau.internal.*;
 import org.apache.juneau.config.encode.*;
 
 /**
@@ -65,7 +66,7 @@ public enum ConfigMod {
 	 * @return The list of modifiers, or an empty list if the string is empty or <jk>null</jk>.
 	 */
 	public static List<ConfigMod> asModifiersReverse(String s) {
-		if (StringUtils.isEmpty(s))
+		if (isEmpty(s))
 			return Collections.emptyList();
 		if (s.length() == 1) {
 			ConfigMod m = fromChar(s.charAt(0));
@@ -87,7 +88,7 @@ public enum ConfigMod {
 	 * @return The list of modifiers, or an empty list if the string is empty or <jk>null</jk>.
 	 */
 	public static List<ConfigMod> asModifiers(String s) {
-		if (StringUtils.isEmpty(s))
+		if (isEmpty(s))
 			return Collections.emptyList();
 		if (s.length() == 1) {
 			ConfigMod m = fromChar(s.charAt(0));
diff --git a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/event/ConfigEvent.java b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/event/ConfigEvent.java
index 1870dfa..2e72079 100644
--- a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/event/ConfigEvent.java
+++ b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/event/ConfigEvent.java
@@ -12,6 +12,7 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.config.event;
 
+import static org.apache.juneau.internal.StringUtils.*;
 import static org.apache.juneau.config.event.ConfigEventType.*;
 
 import java.util.*;
@@ -204,7 +205,7 @@ public class ConfigEvent {
 				if (val.indexOf('#') != -1)
 					val = val.replaceAll("#", "\\\\#");
 				out.append(val);
-				if (! StringUtils.isEmpty(comment)) 
+				if (isNotEmpty(comment)) 
 					out.append(" # ").append(comment);
 				out.append(')');
 				return out.toString();
diff --git a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/internal/ConfigEntry.java b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/internal/ConfigEntry.java
index 45c3e06..06090c4 100644
--- a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/internal/ConfigEntry.java
+++ b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/internal/ConfigEntry.java
@@ -156,7 +156,7 @@ public class ConfigEntry {
 				}
 			}
 				
-			if (! isEmpty(comment)) 
+			if (isNotEmpty(comment)) 
 				w.append(" # ").append(comment);
 			
 			w.append('\n');
diff --git a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigFileStore.java b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigFileStore.java
index e87e57c..7ccfe9e 100644
--- a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigFileStore.java
+++ b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigFileStore.java
@@ -255,7 +255,7 @@ public class ConfigFileStore extends ConfigStore {
 		boolean exists = Files.exists(p);
 		
 		// Don't create the file if we're not going to match.
-		if ((!exists) && (!isEmpty(expectedContents)))
+		if ((!exists) && isNotEmpty(expectedContents))
 			return "";
 		
 		if (isWritable(p)) {
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 c5927f7..ba63fac 100755
--- 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
@@ -17,6 +17,7 @@ import static org.junit.Assert.*;
 import java.util.*;
 
 import org.apache.juneau.*;
+import org.apache.juneau.httppart.uon.*;
 import org.apache.juneau.json.*;
 import org.junit.*;
 
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 a91d85a..0b38c7b 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
@@ -20,6 +20,7 @@ import org.apache.juneau.annotation.*;
 import org.apache.juneau.html.*;
 import org.apache.juneau.html.annotation.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.uon.*;
 import org.apache.juneau.utils.*;
 
 /**
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Contact.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Contact.java
index 23daa40..78abf23 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Contact.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Contact.java
@@ -221,7 +221,7 @@ public class Contact extends SwaggerElement {
 	 * @return <jk>true</jk> if the name property is not null or empty.
 	 */
 	public boolean hasName() {
-		return ! isEmpty(name);
+		return isNotEmpty(name);
 	}
 
 	/**
@@ -239,7 +239,7 @@ public class Contact extends SwaggerElement {
 	 * @return <jk>true</jk> if the email property is not null or empty.
 	 */
 	public boolean hasEmail() {
-		return ! isEmpty(email);
+		return isNotEmpty(email);
 	}
 
 	@Override /* SwaggerElement */
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ExternalDocumentation.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ExternalDocumentation.java
index c95e0d9..2546bb1 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ExternalDocumentation.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ExternalDocumentation.java
@@ -190,7 +190,7 @@ public class ExternalDocumentation extends SwaggerElement {
 	 * @return <jk>true</jk> if the description property is not null or empty.
 	 */
 	public boolean hasDescription() {
-		return ! isEmpty(description);
+		return isNotEmpty(description);
 	}
 
 	@Override /* SwaggerElement */
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Info.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Info.java
index 4868796..ff6ec0b 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Info.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Info.java
@@ -380,7 +380,7 @@ public class Info extends SwaggerElement {
 	 * @return <jk>true</jk> if the title property is not null or empty.
 	 */
 	public boolean hasTitle() {
-		return ! isEmpty(title);
+		return isNotEmpty(title);
 	}
 
 	/**
@@ -389,7 +389,7 @@ public class Info extends SwaggerElement {
 	 * @return <jk>true</jk> if the description property is not null or empty.
 	 */
 	public boolean hasDescription() {
-		return ! isEmpty(description);
+		return isNotEmpty(description);
 	}
 
 	/**
@@ -398,7 +398,7 @@ public class Info extends SwaggerElement {
 	 * @return <jk>true</jk> if the version property is not null or empty.
 	 */
 	public boolean hasVersion() {
-		return ! isEmpty(version);
+		return isNotEmpty(version);
 	}
 
 	/**
@@ -407,7 +407,7 @@ public class Info extends SwaggerElement {
 	 * @return <jk>true</jk> if the termsOfService property is not null or empty.
 	 */
 	public boolean hasTermsOfService() {
-		return ! isEmpty(termsOfService);
+		return isNotEmpty(termsOfService);
 	}
 
 	@Override /* SwaggerElement */
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/License.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/License.java
index cf35643..7e4f9b6 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/License.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/License.java
@@ -179,7 +179,7 @@ public class License extends SwaggerElement {
 	 * @return <jk>true</jk> if the name property is not null or empty.
 	 */
 	public boolean hasName() {
-		return ! isEmpty(name);
+		return isNotEmpty(name);
 	}
 
 	/**
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Operation.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Operation.java
index a896ee1..6e20de1 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Operation.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Operation.java
@@ -1090,7 +1090,7 @@ public class Operation extends SwaggerElement {
 	 * @return <jk>true</jk> if the summary property is not null or empty.
 	 */
 	public boolean hasSummary() {
-		return ! isEmpty(summary);
+		return isNotEmpty(summary);
 	}
 
 	/**
@@ -1099,7 +1099,7 @@ public class Operation extends SwaggerElement {
 	 * @return <jk>true</jk> if the description property is not null or empty.
 	 */
 	public boolean hasDescription() {
-		return ! isEmpty(description);
+		return isNotEmpty(description);
 	}
 
 	/**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
index e15aedb..ea19586 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
@@ -469,7 +469,7 @@ public class BeanMeta<T> {
 		private String findPropertyName(Field f, Set<String> fixedBeanProps) {
 			BeanProperty bp = f.getAnnotation(BeanProperty.class);
 			String name = bpName(bp);
-			if (! isEmpty(name)) {
+			if (isNotEmpty(name)) {
 				if (fixedBeanProps.isEmpty() || fixedBeanProps.contains(name))
 					return name;
 				return null;  // Could happen if filtered via BEAN_includeProperties/BEAN_excludeProperties.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
index 5dc8b02..cdb9125 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
@@ -490,6 +490,8 @@ public class BeanSession extends Session {
 							return (T)new AtomicInteger(Integer.valueOf(n));
 						if (tc == AtomicLong.class)
 							return (T)new AtomicLong(Long.valueOf(n));
+						if (tc == Number.class)
+							return (T)StringUtils.parseNumber(n, Number.class);
 					}
 				}
 			}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ObjectList.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ObjectList.java
index 8e129ae..2550ba8 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ObjectList.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ObjectList.java
@@ -12,11 +12,12 @@
 // ***************************************************************************************************************************
 package org.apache.juneau;
 
+import static org.apache.juneau.internal.StringUtils.*;
+
 import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
 
-import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.serializer.*;
@@ -275,7 +276,7 @@ public class ObjectList extends LinkedList<Object> {
 	 */
 	public ObjectList appendIfNotEmpty(String...o) {
 		for (String s : o)
-			if (! StringUtils.isEmpty(s))
+			if (isNotEmpty(s))
 				add(s);
 		return this;
 	}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ObjectMap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ObjectMap.java
index cdf2ee0..b37d41c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ObjectMap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ObjectMap.java
@@ -332,10 +332,7 @@ public class ObjectMap extends LinkedHashMap<String,Object> {
 	 * Convenience method for adding an entry to this map.
 	 * 
 	 * <p>
-	 * Equivalent to calling {@code put(key, value)}, but returns this map so that the method can be chained.
-	 * 
-	 * <p>
-	 * <jk>null</jk> and empty string/map/collection values are skipped.
+	 * A no-op if the value is <jk>null</jk> or an empty string/map/collection.
 	 * 
 	 * @param key The key.
 	 * @param value The value.
@@ -349,6 +346,54 @@ public class ObjectMap extends LinkedHashMap<String,Object> {
 	 * Convenience method for adding an entry to this map.
 	 * 
 	 * <p>
+	 * A no-op if the value is <jk>false</jk>.
+	 * 
+	 * @param key The key.
+	 * @param value The value.
+	 * @return This object (for method chaining).
+	 */
+	public ObjectMap appendSkipFalse(String key, boolean value) {
+		if (value) 
+			append(key, value);
+		return this;
+	}
+
+	/**
+	 * Convenience method for adding an entry to this map.
+	 * 
+	 * <p>
+	 * A no-op if the value is <code>-1</code>.
+	 * 
+	 * @param key The key.
+	 * @param value The value.
+	 * @return This object (for method chaining).
+	 */
+	public ObjectMap appendSkipMinusOne(String key, long value) {
+		if (value != -1) 
+			append(key, value);
+		return this;
+	}
+
+	/**
+	 * Convenience method for adding an entry to this map.
+	 * 
+	 * <p>
+	 * A no-op if the value is <code>-1</code>.
+	 * 
+	 * @param key The key.
+	 * @param value The value.
+	 * @return This object (for method chaining).
+	 */
+	public ObjectMap appendSkipMinusOne(String key, int value) {
+		if (value != -1) 
+			append(key, value);
+		return this;
+	}
+
+	/**
+	 * Convenience method for adding an entry to this map.
+	 * 
+	 * <p>
 	 * Equivalent to calling {@code put(key, value)}, but returns this map so that the method can be chained.
 	 * 
 	 * <p>
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 ce67d94..b3bae5e 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
@@ -21,7 +21,8 @@ import org.apache.juneau.parser.*;
  * <p>
  * The following default implementations are provided:
  * <ul class='doctree'>
- * 	<li class='jc'>{@link org.apache.juneau.httppart.UonPartParser} - Parts encoded in UON notation.
+ * 	<li class='jc'>{@link org.apache.juneau.httppart.oapi.OapiPartParser} - Parts encoded in based on OpenAPI schema.
+ * 	<li class='jc'>{@link org.apache.juneau.httppart.uon.UonPartParser} - Parts encoded in UON notation.
  * 	<li class='jc'>{@link org.apache.juneau.httppart.SimplePartParser} - Parts encoded in plain text.
  * </ul>
  * 
@@ -43,10 +44,14 @@ public interface HttpPartParser {
 	 * Converts the specified input to the specified class type.
 	 * 
 	 * @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
 	 */
-	public <T> T parse(HttpPartType partType, String in, ClassMeta<T> type) throws ParseException;
+	public <T> T parse(HttpPartType partType, HttpPartSchema schema, String in, ClassMeta<T> type) throws ParseException;
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java
new file mode 100644
index 0000000..5682d11
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java
@@ -0,0 +1,1316 @@
+// ***************************************************************************************************************************
+// * 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 static java.util.Collections.*;
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.regex.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.httppart.oapi.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.utils.*;
+
+/**
+ * Represents an OpenAPI schema definition.
+ * 
+ * <p>
+ * The schema definition can be applied to any HTTP parts such as bodies, headers, query/form parameters, and URL path parts.
+ * <br>The API is generic enough to apply to any path part although some attributes may only applicable for certain parts.
+ * 
+ * <p>
+ * Schema objects are created via builders instantiated through the {@link #create()} method.
+ * 
+ * <p>
+ * This class is thread safe and reusable.
+ */
+public class HttpPartSchema {
+	
+	//-------------------------------------------------------------------------------------------------------------------
+	// Predefined instances
+	//-------------------------------------------------------------------------------------------------------------------
+
+	/** Reusable instance of {@link OapiPartSerializer}, all default settings. */
+	public static final HttpPartSchema DEFAULT = HttpPartSchema.create().build();
+
+	final String _default;
+	final Set<String> _enum;
+	final Map<String,HttpPartSchema> properties;
+	final Boolean allowEmptyValue, exclusiveMaximum, exclusiveMinimum, required, uniqueItems;
+	final CollectionFormat collectionFormat;
+	final Type type;
+	final Format format;
+	final Pattern pattern;
+	final HttpPartSchema items, additionalProperties;
+	final Number maximum, minimum, multipleOf;
+	final Integer maxItems, maxLength, maxProperties, minItems, minLength, minProperties;
+	
+	/**
+	 * Instantiates a new builder for this object.
+	 * 
+	 * @return A new builder for this object.
+	 */
+	public static Builder create() {
+		return new Builder();
+	}
+	
+	HttpPartSchema(Builder b) {
+		this._default = b._default; 
+		this._enum = copy(b._enum);
+		this.properties = build(b.properties);
+		this.allowEmptyValue = b.allowEmptyValue;
+		this.exclusiveMaximum = b.exclusiveMaximum;
+		this.exclusiveMinimum = b.exclusiveMinimum;
+		this.required = b.required;
+		this.uniqueItems = b.uniqueItems;
+		this.collectionFormat = b.collectionFormat;
+		this.type = b.type;
+		this.format = b.format;
+		this.pattern = b.pattern;
+		this.items = build(b.items);
+		this.additionalProperties = build(b.additionalProperties);
+		this.maximum = b.maximum;
+		this.minimum = b.minimum;
+		this.multipleOf = b.multipleOf;
+		this.maxItems = b.maxItems;
+		this.maxLength = b.maxLength;
+		this.maxProperties = b.maxProperties;
+		this.minItems = b.minItems;
+		this.minLength = b.minLength;
+		this.minProperties = b.minProperties;
+		
+		if (b.noValidate)
+			return;
+		
+		// Validation.
+		List<String> errors = new ArrayList<>();
+		AList<String> notAllowed = new AList<>();
+		boolean invalidFormat = false;
+		switch (type) {
+			case STRING: {
+				notAllowed.appendIf(properties != null, "properties");
+				notAllowed.appendIf(additionalProperties != null, "additionalProperties");
+				notAllowed.appendIf(exclusiveMaximum != null, "exclusiveMaximum");
+				notAllowed.appendIf(exclusiveMinimum != null, "exclusiveMinimum");
+				notAllowed.appendIf(uniqueItems != null, "uniqueItems");
+				notAllowed.appendIf(collectionFormat != CollectionFormat.NONE, "collectionFormat");
+				notAllowed.appendIf(items != null, "items");
+				notAllowed.appendIf(maximum != null, "maximum");
+				notAllowed.appendIf(minimum != null, "minimum");
+				notAllowed.appendIf(multipleOf != null, "multipleOf");
+				notAllowed.appendIf(maxItems != null, "maxItems");
+				notAllowed.appendIf(minItems != null, "minItems");
+				notAllowed.appendIf(minProperties != null, "minProperties");
+				invalidFormat = ! format.isOneOf(Format.BYTE, Format.BINARY, Format.DATE, Format.DATE_TIME, Format.PASSWORD, Format.UON, Format.NONE);
+				break;
+			}
+			case ARRAY: {
+				notAllowed.appendIf(properties != null, "properties");
+				notAllowed.appendIf(additionalProperties != null, "additionalProperties");
+				notAllowed.appendIf(exclusiveMaximum != null, "exclusiveMaximum");
+				notAllowed.appendIf(exclusiveMinimum != null, "exclusiveMinimum");
+				notAllowed.appendIf(pattern != null, "pattern");
+				notAllowed.appendIf(maximum != null, "maximum");
+				notAllowed.appendIf(minimum != null, "minimum");
+				notAllowed.appendIf(multipleOf != null, "multipleOf");
+				notAllowed.appendIf(maxLength != null, "maxLength");
+				notAllowed.appendIf(minLength != null, "minLength");
+				notAllowed.appendIf(maxProperties != null, "maxProperties");
+				notAllowed.appendIf(minProperties != null, "minProperties");
+				invalidFormat = ! format.isOneOf(Format.NONE, Format.UON);
+				break;
+			}
+			case BOOLEAN: {
+				notAllowed.appendIf(_enum != null, "_enum");
+				notAllowed.appendIf(properties != null, "properties");
+				notAllowed.appendIf(additionalProperties != null, "additionalProperties");
+				notAllowed.appendIf(exclusiveMaximum != null, "exclusiveMaximum");
+				notAllowed.appendIf(exclusiveMinimum != null, "exclusiveMinimum");
+				notAllowed.appendIf(uniqueItems != null, "uniqueItems");
+				notAllowed.appendIf(collectionFormat != CollectionFormat.NONE, "collectionFormat");
+				notAllowed.appendIf(pattern != null, "pattern");
+				notAllowed.appendIf(items != null, "items");
+				notAllowed.appendIf(maximum != null, "maximum");
+				notAllowed.appendIf(minimum != null, "minimum");
+				notAllowed.appendIf(multipleOf != null, "multipleOf");
+				notAllowed.appendIf(maxItems != null, "maxItems");
+				notAllowed.appendIf(maxLength != null, "maxLength");
+				notAllowed.appendIf(maxProperties != null, "maxProperties");
+				notAllowed.appendIf(minItems != null, "minItems");
+				notAllowed.appendIf(minLength != null, "minLength");
+				notAllowed.appendIf(minProperties != null, "minProperties");
+				invalidFormat = ! format.isOneOf(Format.NONE);
+				break;
+			}
+			case FILE: {
+				break;
+			}
+			case INTEGER: {
+				notAllowed.appendIf(properties != null, "properties");
+				notAllowed.appendIf(additionalProperties != null, "additionalProperties");
+				notAllowed.appendIf(uniqueItems != null, "uniqueItems");
+				notAllowed.appendIf(collectionFormat != CollectionFormat.NONE, "collectionFormat");
+				notAllowed.appendIf(pattern != null, "pattern");
+				notAllowed.appendIf(items != null, "items");
+				notAllowed.appendIf(maxItems != null, "maxItems");
+				notAllowed.appendIf(maxLength != null, "maxLength");
+				notAllowed.appendIf(maxProperties != null, "maxProperties");
+				notAllowed.appendIf(minItems != null, "minItems");
+				notAllowed.appendIf(minLength != null, "minLength");
+				notAllowed.appendIf(minProperties != null, "minProperties");
+				invalidFormat = ! format.isOneOf(Format.NONE, Format.INT32, Format.INT64);
+				break;
+			}
+			case NUMBER: {
+				notAllowed.appendIf(properties != null, "properties");
+				notAllowed.appendIf(additionalProperties != null, "additionalProperties");
+				notAllowed.appendIf(uniqueItems != null, "uniqueItems");
+				notAllowed.appendIf(collectionFormat != CollectionFormat.NONE, "collectionFormat");
+				notAllowed.appendIf(pattern != null, "pattern");
+				notAllowed.appendIf(items != null, "items");
+				notAllowed.appendIf(maxItems != null, "maxItems");
+				notAllowed.appendIf(maxLength != null, "maxLength");
+				notAllowed.appendIf(maxProperties != null, "maxProperties");
+				notAllowed.appendIf(minItems != null, "minItems");
+				notAllowed.appendIf(minLength != null, "minLength");
+				notAllowed.appendIf(minProperties != null, "minProperties");
+				invalidFormat = ! format.isOneOf(Format.NONE, Format.FLOAT, Format.DOUBLE);
+				break;
+			}
+			case OBJECT: {
+				notAllowed.appendIf(exclusiveMaximum != null, "exclusiveMaximum");
+				notAllowed.appendIf(exclusiveMinimum != null, "exclusiveMinimum");
+				notAllowed.appendIf(uniqueItems != null, "uniqueItems");
+				notAllowed.appendIf(collectionFormat != CollectionFormat.NONE, "collectionFormat");
+				notAllowed.appendIf(pattern != null, "pattern");
+				notAllowed.appendIf(items != null, "items");
+				notAllowed.appendIf(maximum != null, "maximum");
+				notAllowed.appendIf(minimum != null, "minimum");
+				notAllowed.appendIf(multipleOf != null, "multipleOf");
+				notAllowed.appendIf(maxItems != null, "maxItems");
+				notAllowed.appendIf(maxLength != null, "maxLength");
+				notAllowed.appendIf(minItems != null, "minItems");
+				notAllowed.appendIf(minLength != null, "minLength");
+				invalidFormat = ! format.isOneOf(Format.NONE, Format.UON);
+				break;
+			}
+			default:
+				break;
+		}
+
+		if (! notAllowed.isEmpty())
+			errors.add("Attributes not allow for type='"+type+"': " + StringUtils.join(notAllowed, ","));
+		if (invalidFormat)
+			errors.add("Invalid format for type='"+type+"': '"+format+"'");
+		if (exclusiveMaximum != null && maximum == null)
+			errors.add("Cannot specify exclusiveMaximum with maximum.");
+		if (exclusiveMinimum != null && minimum == null)
+			errors.add("Cannot specify exclusiveMinimum with minimum.");
+		if (required != null && required && _default != null)
+			errors.add("Cannot specify a default value on a required value.");
+		
+		if (! errors.isEmpty())
+			throw new ContextRuntimeException("Schema specification errors: \n\t" + join(errors, "\n\t")); 
+	}
+	
+	/**
+	 * The builder class for creating {@link HttpPartSchema} objects.
+	 * 
+	 */
+	public static class Builder {
+		String _default;
+		Set<String> _enum;
+		Boolean allowEmptyValue, exclusiveMaximum, exclusiveMinimum, required, uniqueItems;
+		CollectionFormat collectionFormat = CollectionFormat.NONE;
+		Type type = Type.NONE;
+		Format format = Format.NONE;
+		Pattern pattern;
+		Number maximum, minimum, multipleOf;
+		Integer maxItems, maxLength, maxProperties, minItems, minLength, minProperties;
+		Map<String,Builder> properties;
+		HttpPartSchema.Builder items, additionalProperties;
+		boolean noValidate;
+		
+		/**
+		 * Instantiates a new {@link HttpPartSchema} object based on the configuration of this builder.
+		 * 
+		 * <p>
+		 * This method can be called multiple times to produce new schema objects.
+		 * 
+		 * @return 
+		 * 	A new {@link HttpPartSchema} object.
+		 * 	<br>Never <jk>null</jk>.
+		 */
+		public HttpPartSchema build() {
+			return new HttpPartSchema(this);
+		}
+
+		/**
+		 * <mk>required</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * Determines whether the parameter is mandatory.
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder required(Boolean value) {
+			if (value != null)
+				this.required = value;
+			return this;
+		}
+	
+		/**
+		 * <mk>type</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * The type of the parameter. 
+		 * 
+		 * <p> 
+		 * The possible values are:
+		 * <ul class='spaced-list'>
+		 * 	<li>
+		 * 		<js>"string"</js>
+		 * 		<br>Parameter must be a string or a POJO convertible from a string.
+		 * 	<li>
+		 * 		<js>"number"</js>
+		 * 		<br>Parameter must be a number primitive or number object.
+		 * 		<br>If parameter is <code>Object</code>, creates either a <code>Float</code> or <code>Double</code> depending on the size of the number.
+		 * 	<li>
+		 * 		<js>"integer"</js>
+		 * 		<br>Parameter must be a integer/long primitive or integer/long object.
+		 * 		<br>If parameter is <code>Object</code>, creates either a <code>Short</code>, <code>Integer</code>, or <code>Long</code> depending on the size of the number.
+		 * 	<li>
+		 * 		<js>"boolean"</js>
+		 * 		<br>Parameter must be a boolean primitive or object.
+		 * 	<li>
+		 * 		<js>"array"</js>
+		 * 		<br>Parameter must be an array or collection.
+		 * 		<br>Elements must be strings or POJOs convertible from strings.
+		 * 		<br>If parameter is <code>Object</code>, creates an {@link ObjectList}.
+		 * 	<li>
+		 * 		<js>"object"</js>
+		 * 		<br>Parameter must be a map or bean.
+		 * 		<br>If parameter is <code>Object</code>, creates an {@link ObjectMap}.
+		 * 		<br>Note that this is an extension of the OpenAPI schema as Juneau allows for arbitrarily-complex POJOs to be serialized as HTTP parts.
+		 * 	<li>
+		 * 		<js>"file"</js>
+		 * 		<br>This type is currently not supported.
+		 * </ul>
+		 * 
+		 * <p>
+		 * If the type is not specified, it will be auto-detected based on the parameter class type.
+		 * 
+		 * <h5 class='section'>See Also:</h5>
+		 * <ul class='doctree'>
+		 * 	<li class='link'><a class='doclink' href='https://swagger.io/specification/#dataTypes'>Swagger specification &gt; Data Types</a>
+		 * </ul>
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder type(String value) {
+			try {
+				if (isNotEmpty(value))
+					this.type = Type.fromString(value);
+			} catch (Exception e) {
+				throw new ContextRuntimeException("Invalid value ''{0}'' passed in as type value.  Valid values: {1}", value, Type.values()); 
+			}
+			return this;
+		}
+	
+		/**
+		 * <mk>format</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * The extending format for the previously mentioned <a href='https://swagger.io/specification/v2/#parameterType'>type</a>. 
+		 * 
+		 * <p> 
+		 * The possible values are:
+		 * <ul class='spaced-list'>
+		 * 	<li>
+		 * 		<js>"int32"</js> - Signed 32 bits.
+		 * 		<br>Only valid with type <js>"integer"</js>.
+		 * 	<li>
+		 * 		<js>"int64"</js> - Signed 64 bits.
+		 * 		<br>Only valid with type <js>"integer"</js>.
+		 * 	<li>
+		 * 		<js>"float"</js> - 32-bit floating point number.
+		 * 		<br>Only valid with type <js>"number"</js>.
+		 * 	<li>
+		 * 		<js>"double"</js> - 64-bit floating point number.
+		 * 		<br>Only valid with type <js>"number"</js>.
+		 * 	<li>
+		 * 		<js>"byte"</js> - BASE-64 encoded characters.
+		 * 		<br>Only valid with type <js>"string"</js>.
+		 * 		<br>Parameters of type POJO convertible from string are converted after the string has been decoded.
+		 * 	<li>
+		 * 		<js>"binary"</js> - Hexadecimal encoded octets (e.g. <js>"00FF"</js>).
+		 * 		<br>Only valid with type <js>"string"</js>.
+		 * 		<br>Parameters of type POJO convertible from string are converted after the string has been decoded.
+		 * 	<li>
+		 * 		<js>"date"</js> - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 full-date</a>.
+		 * 		<br>Only valid with type <js>"string"</js>.
+		 * 	<li>
+		 * 		<js>"date-time"</js> - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 date-time</a>.
+		 * 		<br>Only valid with type <js>"string"</js>.
+		 * 	<li>
+		 * 		<js>"password"</js> - Used to hint UIs the input needs to be obscured.
+		 * 		<br>This format does not affect the serialization or parsing of the parameter.
+		 * 	<li>
+		 * 		<js>"uon"</js> - UON notation (e.g. <js>"(foo=bar,baz=@(qux,123))"</js>). 
+		 * 		<br>Only valid with type <js>"object"</js>.
+		 * 		<br>If not specified, then the input is interpreted as plain-text and is converted to a POJO directly.
+		 * </ul>
+		 * 
+		 * <h5 class='section'>See Also:</h5>
+		 * <ul class='doctree'>
+		 * 	<li class='link'><a class='doclink' href='https://swagger.io/specification/v2/#dataTypeFormat'>Swagger specification &gt; Data Type Formats</a>
+		 * </ul>
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder format(String value) {
+			try {
+				if (isNotEmpty(value))
+					this.format = Format.fromString(value);
+			} catch (Exception e) {
+				throw new ContextRuntimeException("Invalid value ''{0}'' passed in as format value.  Valid values: {1}", value, Format.values()); 
+			}
+			return this;
+		}
+	
+		/**
+		 * <mk>allowEmptyValue</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * Sets the ability to pass empty-valued parameters. 
+		 * <br>This is valid only for either query or formData parameters and allows you to send a parameter with a name only or an empty value. 
+		 * <br>The default value is <jk>false</jk>.
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder allowEmptyValue(Boolean value) {
+			if (value != null)
+				this.allowEmptyValue = value;
+			return this;
+		}
+	
+		/**
+		 * <mk>items</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * Describes the type of items in the array.
+		 * <p>
+		 * Required if <code>type</code> is <js>"array"</js>. 
+		 * <br>Can only be used if <code>type</code> is <js>"array"</js>.
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder items(Builder value) {
+			if (value != null)
+				items = value;
+			return this;
+		}
+
+		/**
+		 * <mk>collectionFormat</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * Determines the format of the array if <code>type</code> <js>"array"</js> is used. 
+		 * <br>Can only be used if <code>type</code> is <js>"array"</js>.
+		 * 
+		 * <br>Possible values are:
+		 * <ul class='spaced-list'>
+		 * 	<li>
+		 * 		<js>"csv"</js> (default) - Comma-separated values (e.g. <js>"foo,bar"</js>).
+		 * 	<li>
+		 * 		<js>"ssv"</js> - Space-separated values (e.g. <js>"foo bar"</js>).
+		 * 	<li>
+		 * 		<js>"tsv"</js> - Tab-separated values (e.g. <js>"foo\tbar"</js>).
+		 * 	<li>
+		 * 		<js>"pipes</js> - Pipe-separated values (e.g. <js>"foo|bar"</js>).
+		 * 	<li>
+		 * 		<js>"multi"</js> - Corresponds to multiple parameter instances instead of multiple values for a single instance (e.g. <js>"foo=bar&amp;foo=baz"</js>). 
+		 * 	<li>
+		 * 		<js>"uon"</js> - UON notation (e.g. <js>"@(foo,bar)"</js>). 
+		 * 	<li>
+		 * </ul>
+		 * 
+		 * <p>
+		 * Note that for collections/arrays parameters with POJO element types, the input is broken into a string array before being converted into POJO elements. 
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder collectionFormat(String value) {
+			try {
+				if (isNotEmpty(value))
+					this.collectionFormat = CollectionFormat.fromString(value);
+			} catch (Exception e) {
+				throw new ContextRuntimeException("Invalid value ''{0}'' passed in as collectionFormat value.  Valid values: {1}", value, CollectionFormat.values()); 
+			}
+			return this;
+		}
+	
+		/**
+		 * <mk>default</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * Declares the value of the parameter that the server will use if none is provided, for example a "count" to control the number of results per page might default to 100 if not supplied by the client in the request. 
+		 * <br>(Note: "default" has no meaning for required parameters.) 
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder _default(String value) {
+			if (isNotEmpty(value))
+				this._default = value;
+			return this;
+		}
+	
+		/**
+		 * <mk>maximum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * Defines the maximum value for a parameter of numeric types.
+		 * 
+		 * <p>
+		 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder maximum(Number value) {
+			if (value != null)
+				this.maximum = value;
+			return this;
+		}
+	
+		/**
+		 * <mk>exclusiveMaximum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * Defines whether the maximum is matched exclusively.
+		 * 
+		 * <p>
+		 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
+		 * <br>If <jk>true</jk>, must be accompanied with <code>maximum</code>.
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder exclusiveMaximum(Boolean value) {
+			if (value != null)
+				this.exclusiveMaximum = value;
+			return this;
+		}
+	
+		/**
+		 * <mk>minimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * Defines the minimum value for a parameter of numeric types.
+		 * 
+		 * <p>
+		 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder minimum(Number value) {
+			if (value != null)
+				this.minimum = value;
+			return this;
+		}
+	
+		/**
+		 * <mk>exclusiveMinimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * Defines whether the minimum is matched exclusively.
+		 * 
+		 * <p>
+		 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
+		 * <br>If <jk>true</jk>, must be accompanied with <code>minimum</code>.
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder exclusiveMinimum(Boolean value) {
+			if (value != null)
+				this.exclusiveMinimum = value;
+			return this;
+		}
+	
+		/**
+		 * <mk>maxLength</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * A string instance is valid against this keyword if its length is less than, or equal to, the value of this keyword.
+		 * <br>The length of a string instance is defined as the number of its characters as defined by <a href='https://tools.ietf.org/html/rfc4627'>RFC 4627</a>.
+		 * 
+		 * <p>
+		 * Only allowed for the following types: <js>"string"</js>.
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder maxLength(Integer value) {
+			if (value != null)
+				this.maxLength = value;
+			return this;
+		}
+	
+		/**
+		 * <mk>minLength</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * A string instance is valid against this keyword if its length is greater than, or equal to, the value of this keyword.
+		 * <br>The length of a string instance is defined as the number of its characters as defined by <a href='https://tools.ietf.org/html/rfc4627'>RFC 4627</a>.
+		 * 
+		 * <p>
+		 * Only allowed for the following types: <js>"string"</js>.
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder minLength(Integer value) {
+			if (value != null)
+				this.minLength = value;
+			return this;
+		}
+	
+		/**
+		 * <mk>pattern</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * A string input is valid if it matches the specified regular expression pattern.
+		 * 
+		 * <p>
+		 * Only allowed for the following types: <js>"string"</js>.
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder pattern(String value) {
+			try {
+				if (isNotEmpty(value))
+					this.pattern = Pattern.compile(value);
+			} catch (Exception e) {
+				throw new ContextRuntimeException(e, "Invalid value {0} passed in as pattern value.  Must be a valid regular expression.", value); 
+			}
+			return this;
+		}
+
+		/**
+		 * <mk>maxItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * An array or collection is valid if its size is less than, or equal to, the value of this keyword.
+		 * 
+		 * <p>
+		 * Only allowed for the following types: <js>"array"</js>.
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder maxItems(Integer value) {
+			if (value != null)
+				this.maxItems = value;
+			return this;
+		}
+	
+		/**
+		 * <mk>minItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * An array or collection is valid if its size is greater than, or equal to, the value of this keyword.
+		 * 
+		 * <p>
+		 * Only allowed for the following types: <js>"array"</js>.
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder minItems(Integer value) {
+			if (value != null)
+				this.minItems = value;
+			return this;
+		}
+	
+		/**
+		 * <mk>uniqueItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * If <jk>true</jk>, the input validates successfully if all of its elements are unique.
+		 * 
+		 * <p>
+		 * <br>If the parameter type is a subclass of {@link Set}, this validation is skipped (since a set can only contain unique items anyway).
+		 * <br>Otherwise, the collection or array is checked for duplicate items.
+		 * 
+		 * <p>
+		 * Only allowed for the following types: <js>"array"</js>.
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder uniqueItems(Boolean value) {
+			if (value != null)
+				this.uniqueItems = value;
+			return this;
+		}
+	
+		/**
+		 * <mk>enum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * If specified, the input validates successfully if it is equal to one of the elements in this array.
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder _enum(Set<String> value) {
+			if (value != null)
+				this._enum = value;
+			return this;
+		}
+	
+		/**
+		 * <mk>multipleOf</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+		 * 
+		 * <p>
+		 * A numeric instance is valid if the result of the division of the instance by this keyword's value is an integer.
+		 * 
+		 * <p>
+		 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder multipleOf(Number value) {
+			if (value != null)
+				this.multipleOf = value;
+			return this;
+		}
+	
+		/**
+		 * TODO
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder maxProperties(Integer value) {
+			if (value != null)
+				this.maxProperties = value;
+			return this;
+		}
+	
+		/**
+		 * TODO
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder minProperties(Integer value) {
+			if (value != null)
+				this.minProperties = value;
+			return this;
+		}
+	
+		/**
+		 * TODO
+		 * 
+		 * @param name The property name.
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder property(String name, Builder value) {
+			if (isNotEmpty(name) && isNotEmpty(value))
+				properties.put(name, value);
+			return this;
+		}
+	
+		/**
+		 * TODO
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder additionalProperties(Builder value) {
+			if (value != null)
+				additionalProperties = value;
+			return additionalProperties;
+		}
+		
+		/**
+		 * TODO
+		 * 
+		 * @param value 
+		 * 	The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder noValidate(boolean value) {
+			this.noValidate = value;
+			return this;
+		}
+	}
+	
+	/**
+	 * Valid values for the <code>collectionFormat</code> field.
+	 */
+	public static enum CollectionFormat {
+		
+		/**
+		 * Comma-separated values (e.g. <js>"foo,bar"</js>).
+		 */
+		CSV, 
+		
+		/**
+		 * Space-separated values (e.g. <js>"foo bar"</js>).
+		 */
+		SSV, 
+		
+		/**
+		 * Tab-separated values (e.g. <js>"foo\tbar"</js>).
+		 */
+		TSV, 
+		
+		/**
+		 * Pipe-separated values (e.g. <js>"foo|bar"</js>).
+		 */
+		PIPES, 
+		
+		/**
+		 * Corresponds to multiple parameter instances instead of multiple values for a single instance (e.g. <js>"foo=bar&amp;foo=baz"</js>). 
+		 */
+		MULTI, 
+		
+		/**
+		 * UON notation (e.g. <js>"@(foo,bar)"</js>). 
+		 */
+		UON,
+
+		/**
+		 * Not specified.
+		 */
+		NONE;
+		
+		static CollectionFormat fromString(String value) {
+			
+			return valueOf(value.toUpperCase());
+		}
+		
+		@Override
+		public String toString() {
+			return name().toLowerCase();
+		}
+	}
+	
+	/**
+	 * Valid values for the <code>type</code> field.
+	 */
+	public static enum Type {
+		
+		/**
+		 * String.
+		 */
+		STRING, 
+		
+		/**
+		 * Floating point number.
+		 */
+		NUMBER, 
+		
+		/**
+		 * Decimal number.
+		 */
+		INTEGER, 
+		
+		/**
+		 * Boolean.
+		 */
+		BOOLEAN, 
+		
+		/**
+		 * Array or collection.
+		 */
+		ARRAY, 
+		
+		/**
+		 * Map or bean.
+		 */
+		OBJECT, 
+		
+		/**
+		 * File.
+		 */
+		FILE,
+		
+		/**
+		 * Not specified.
+		 */
+		NONE;
+		
+		static Type fromString(String value) {
+			return valueOf(value.toUpperCase());
+		}
+		
+		@Override
+		public String toString() {
+			return name().toLowerCase();
+		}
+	}
+
+	/**
+	 * Valid values for the <code>format</code> field.
+	 */
+	public static enum Format {
+		
+		/**
+		 * Signed 32 bits.
+		 */
+		INT32, 
+		
+		/**
+		 * Signed 64 bits.
+		 */
+		INT64, 
+		
+		/**
+		 * 32-bit floating point number.
+		 */
+		FLOAT, 
+		
+		/**
+		 * 64-bit floating point number.
+		 */
+		DOUBLE, 
+		
+		/**
+		 * BASE-64 encoded characters.
+		 */
+		BYTE, 
+		
+		/**
+		 * Hexadecimal encoded octets (e.g. <js>"00FF"</js>).
+		 */
+		BINARY, 
+		
+		/**
+		 * An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 full-date</a>.
+		 */
+		DATE, 
+		
+		/**
+		 *  An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 date-time</a>.
+		 */
+		DATE_TIME, 
+		
+		/**
+		 * Used to hint UIs the input needs to be obscured.
+		 */
+		PASSWORD, 
+		
+		/**
+		 * UON notation (e.g. <js>"(foo=bar,baz=@(qux,123))"</js>). 
+		 */
+		UON, 
+
+		/**
+		 * Not specified.
+		 */
+		NONE;
+		
+		static Format fromString(String value) {
+			value = value.toUpperCase().replace('-','_');
+			return valueOf(value);
+		}
+		
+		@Override
+		public String toString() {
+			String s = name().toLowerCase().replace('_','-');
+			return s;
+		}
+		
+		/**
+		 * Returns <jk>true</jk> if this format is in the provided list.
+		 * 
+		 * @param list The list of formats to check against.
+		 * @return <jk>true</jk> if this format is in the provided list.
+		 */
+		public boolean isOneOf(Format...list) {
+			for (Format ff : list)
+				if (this == ff)
+					return true;
+			return false;
+		}
+	}
+
+	/**
+	 * Returns the default value for this schema.
+	 * 
+	 * @return The default value for this schema, or <jk>null</jk> if not specified. 
+	 */
+	public String getDefault() {
+		return _default;
+	}
+
+	/**
+	 * Returns the <code>collectionFormat</code> field of this schema.
+	 * 
+	 * @return The <code>collectionFormat</code> field of this schema.
+	 */
+	public CollectionFormat getCollectionFormat() {
+		return collectionFormat;
+	}
+	
+	/**
+	 * Returns the type field of this schema.
+	 * 
+	 * @param cm 
+	 * 	The class meta of the object.
+	 * 	<br>Used to auto-detect the type if the type was not specified. 
+	 * @return The format field of this schema.
+	 */
+	public Type getType(ClassMeta<?> cm) {
+		if (type != Type.NONE)
+			return type;
+		if (cm.isMapOrBean())
+			return Type.OBJECT;
+		if (cm.isCollectionOrArray())
+			return Type.ARRAY;
+		if (cm.isInteger())
+			return Type.INTEGER;
+		if (cm.isNumber())
+			return Type.NUMBER;
+		if (cm.isBoolean())
+			return Type.BOOLEAN;
+		return Type.STRING;
+	}
+
+	/**
+	 * Returns the <code>format</code> field of this schema.
+	 * 
+	 * @return The <code>format</code> field of this schema.
+	 */
+	public Format getFormat() {
+		return format;
+	}
+	
+	/**
+	 * Returns the schema for child items of the object represented by this schema.
+	 * 
+	 * @return The schema for child items of the object represented by this schema, or <jk>null</jk> if not defined.
+	 */
+	public HttpPartSchema getItems() {
+		return items;
+	}
+	
+	/**
+	 * Throws a {@link ParseException} if the specified pre-parsed input does not validate against this schema.
+	 * 
+	 * @param in The input.
+	 * @return The same object passed in.
+	 * @throws ParseException if the specified pre-parsed input does not validate against this schema.
+	 */
+	public String validateInput(String in) throws ParseException {
+		if (! isValidRequired(in))
+			throw new ParseException("No value specified.");
+		if (in != null) {
+			if (! isValidAllowEmpty(in))
+				throw new ParseException("Empty value not allowed.");
+			if (! isValidPattern(in))
+				throw new ParseException("Value does not match expected pattern.  Must match pattern: {0}", pattern.pattern());
+			if (! isValidEnum(in))
+				throw new ParseException("Value does not match one of the expected values.  Must be one of the following: {0}", _enum);
+			if (! isValidMaxLength(in))
+				throw new ParseException("Maximum length of value exceeded.");
+			if (! isValidMinLength(in))
+				throw new ParseException("Minimum length of value exceeded.");
+		}
+		return in;
+	}
+	
+	/**
+	 * Throws a {@link ParseException} if the specified parsed output does not validate against this schema.
+	 * 
+	 * @param o The parsed output.
+	 * @param bc The bean context used to detect POJO types.
+	 * @return The same object passed in.
+	 * @throws ParseException if the specified parsed output does not validate against this schema.
+	 */
+	@SuppressWarnings("rawtypes")
+	public Object validateOutput(Object o, BeanContext bc) throws ParseException {
+		if (o == null) {
+			if (! isValidRequired(o))
+				throw new ParseException("Required value not provided.");
+			return o;
+		}
+		ClassMeta<?> cm = bc.getClassMetaForObject(o);
+		switch (getType(cm)) {
+			case STRING: {
+				if (cm.isString()) 
+					return validateInput(o.toString());
+				break;
+			}
+			case ARRAY: {
+				if (cm.isArray()) {
+					if (! isValidMinItems(o))
+						throw new ParseException("Minimum items of value exceeded.");
+					if (! isValidMaxItems(o))
+						throw new ParseException("Maximum items of value exceeded.");
+					if (! isValidUniqueItems(o)) 
+						throw new ParseException("Duplicate items found.");
+					HttpPartSchema items = getItems();
+					if (items != null) 
+						for (int i = 0; i < Array.getLength(o); i++)
+							items.validateOutput(Array.get(o, i), bc);
+				} else if (cm.isCollection()) {
+					Collection<?> c = (Collection<?>)o;
+					if (! isValidMinItems(c))
+						throw new ParseException("Minimum items of value exceeded.");
+					if (! isValidMaxItems(c))
+						throw new ParseException("Maximum items of value exceeded.");
+					if (! isValidUniqueItems(c))
+						throw new ParseException("Duplicate items found.");
+					HttpPartSchema items = getItems();
+					if (items != null) 
+						for (Object o2 : c)
+							items.validateOutput(o2, bc);
+				}
+				break;
+			}
+			case INTEGER: {
+				if (cm.isNumber()) {
+					Number n = (Number)o;
+					if (! isValidMinimum(n))
+						throw new ParseException("Minimal value exceeded.");
+					if (! isValidMaximum(n))
+						throw new ParseException("Maximum value exceeded.");
+					if (! isValidMultipleOf(n))
+						throw new ParseException("Multiple-of not met.");
+				}
+				break;
+			}
+			case NUMBER: {
+				if (cm.isNumber()) {
+					Number n = (Number)o;
+					if (! isValidMinimum(n))
+						throw new ParseException("Minimal value exceeded.");
+					if (! isValidMaximum(n))
+						throw new ParseException("Maximum value exceeded.");
+					if (! isValidMultipleOf(n))
+						throw new ParseException("Multiple-of not met.");
+				}
+				break;
+			}
+			case OBJECT: {
+				if (cm.isMapOrBean()) {
+					Map<?,?> m = cm.isMap() ? (Map<?,?>)o : bc.createSession().toBeanMap(o);
+					if (! isValidMinProperties(m))
+						throw new ParseException("Minimum number properties of value not met.");
+					if (! isValidMaxProperties(m))
+						throw new ParseException("Maximum number of properties of value exceeded.");
+					for (Map.Entry e : m.entrySet()) {
+						String key = e.getKey().toString();
+						HttpPartSchema s2 = getProperty(key);
+						if (s2 != null) 
+							s2.validateOutput(e.getValue(), bc);
+					}
+				} else if (cm.isBean()) {
+					
+				}
+				break;
+			}
+			case BOOLEAN: 
+			case FILE: 
+			case NONE: 
+				break;
+		}		
+		return o;
+	}
+	
+	//-----------------------------------------------------------------------------------------------------------------
+	// Helper methods.
+	//-----------------------------------------------------------------------------------------------------------------
+	
+	private boolean isValidRequired(Object x) {
+		return x != null || required == null || ! required;
+	}
+
+	private boolean isValidMinProperties(Map<?,?> x) {
+		return minProperties == null || x.size() >= minProperties;
+	}
+
+	private boolean isValidMaxProperties(Map<?,?> x) {
+		return maxProperties == null || x.size() <= maxProperties;
+	}
+	
+	private boolean isValidMinimum(Number x) {
+		if (x instanceof Integer) 
+			return minimum == null || x.intValue() > minimum.intValue() || (x.intValue() == minimum.intValue() && (exclusiveMinimum == null || ! exclusiveMinimum));
+		if (x instanceof Short)
+			return minimum == null || x.shortValue() > minimum.shortValue() || (x.intValue() == minimum.shortValue() && (exclusiveMinimum == null || ! exclusiveMinimum));
+		if (x instanceof Long)
+			return minimum == null || x.longValue() > minimum.longValue() || (x.intValue() == minimum.longValue() && (exclusiveMinimum == null || ! exclusiveMinimum));
+		if (x instanceof Float)
+			return minimum == null || x.floatValue() > minimum.floatValue() || (x.floatValue() == minimum.floatValue() && (exclusiveMinimum == null || ! exclusiveMinimum));
+		if (x instanceof Double)
+			return minimum == null || x.doubleValue() > minimum.doubleValue() || (x.doubleValue() == minimum.doubleValue() && (exclusiveMinimum == null || ! exclusiveMinimum));
+		return true;
+	}
+	
+	private boolean isValidMaximum(Number x) {
+		if (x instanceof Integer) 
+			return maximum == null || x.intValue() < maximum.intValue() || (x.intValue() == maximum.intValue() && (exclusiveMaximum == null || ! exclusiveMaximum));
+		if (x instanceof Short)
+			return maximum == null || x.shortValue() < maximum.shortValue() || (x.intValue() == maximum.shortValue() && (exclusiveMaximum == null || ! exclusiveMaximum));
+		if (x instanceof Long)
+			return maximum == null || x.longValue() < maximum.longValue() || (x.intValue() == maximum.longValue() && (exclusiveMaximum == null || ! exclusiveMaximum));
+		if (x instanceof Float)
+			return maximum == null || x.floatValue() < maximum.floatValue() || (x.floatValue() == maximum.floatValue() && (exclusiveMaximum == null || ! exclusiveMaximum));
+		if (x instanceof Double)
+			return maximum == null || x.doubleValue() < maximum.doubleValue() || (x.doubleValue() == maximum.doubleValue() && (exclusiveMaximum == null || ! exclusiveMaximum));
+		return true;
+	}
+	
+	private boolean isValidMultipleOf(Number x) {
+		if (x instanceof Integer) 
+			return multipleOf == null || x.intValue() % multipleOf.intValue() == 0;
+		if (x instanceof Short)
+			return multipleOf == null || x.shortValue() % multipleOf.shortValue() == 0;
+		if (x instanceof Long)
+			return multipleOf == null || x.longValue() % multipleOf.longValue() == 0;
+		if (x instanceof Float)
+			return multipleOf == null || x.floatValue() % multipleOf.floatValue() == 0;
+		if (x instanceof Double)
+			return multipleOf == null || x.doubleValue() % multipleOf.doubleValue() == 0;
+		return true;
+	}
+
+	private boolean isValidAllowEmpty(String x) {
+		return allowEmptyValue == null || allowEmptyValue || isNotEmpty(x);
+	}
+	
+	private boolean isValidPattern(String x) {
+		return pattern == null || pattern.matcher(x).matches();
+	}
+	
+	private boolean isValidEnum(String x) {
+		return _enum == null || _enum.contains(x);
+	}
+	
+	private boolean isValidMinLength(String x) {
+		return minLength == null || x.length() >= minLength;
+	}
+
+	private boolean isValidMaxLength(String x) {
+		return maxLength == null || x.length() <= maxLength;
+	}
+
+	private boolean isValidMinItems(Object x) {
+		return minItems == null || Array.getLength(x) >= minItems;
+	}
+
+	private boolean isValidMaxItems(Object x) {
+		return maxItems == null || Array.getLength(x) <= maxItems;
+	}
+
+	private boolean isValidUniqueItems(Object x) {
+		if (uniqueItems != null && uniqueItems) {
+			Set<Object> s = new HashSet<>();
+			for (int i = 0; i < Array.getLength(x); i++) {
+				Object o = Array.get(x, i);
+				if (! s.add(o))
+					return false;
+			}
+		}
+		return true;
+	}
+
+	private boolean isValidMinItems(Collection<?> x) {
+		return minItems == null || x.size() >= minItems;
+	}
+
+	private boolean isValidMaxItems(Collection<?> x) {
+		return maxItems == null || x.size() <= maxItems;
+	}
+
+	private boolean isValidUniqueItems(Collection<?> x) {
+		if (uniqueItems != null && uniqueItems && ! (x instanceof Set)) {
+			Set<Object> s = new HashSet<>();
+			for (Object o : x) 
+				if (! s.add(o))
+					return false;
+		}
+		return true;
+	}
+	
+	private HttpPartSchema getProperty(String name) {
+		if (properties != null) {
+			HttpPartSchema schema = properties.get(name);
+			if (schema != null)
+				return schema;
+		}
+		return additionalProperties;
+	}
+
+	
+	private static Set<String> copy(Set<String> in) {
+		return in == null ? null : unmodifiableSet(new LinkedHashSet<>(in));
+	}
+	
+	private static Map<String,HttpPartSchema> build(Map<String,Builder> in) {
+		if (in == null)
+			return null;
+		Map<String,HttpPartSchema> m = new LinkedHashMap<>();
+		for (Map.Entry<String,Builder> e : in.entrySet()) 
+			m.put(e.getKey(), e.getValue().build());
+		return unmodifiableMap(m);
+	}
+
+	private static HttpPartSchema build(Builder in) {
+		return in == null ? null : in.build();
+	}
+}
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 93e256e..ac6bbf7 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
@@ -22,8 +22,9 @@ import org.apache.juneau.remoteable.*;
  * <p>
  * The following default implementations are provided:
  * <ul class='doctree'>
- * 	<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
+ * 	<li class='jc'>{@link org.apache.juneau.httppart.oapi.OapiPartSerializer} - Parts encoded based on OpenAPI schema.
+ * 	<li class='jc'>{@link org.apache.juneau.httppart.uon.UonPartSerializer} - Parts encoded in UON notation.
+ * 	<li class='jc'>{@link org.apache.juneau.httppart.uon.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>
@@ -64,8 +65,12 @@ public interface HttpPartSerializer {
 	 * Returned values should NOT be URL-encoded.
 	 * 
 	 * @param type The category of value being serialized.
-	 * @param value The 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.
 	 */
-	public String serialize(HttpPartType type, Object value);
+	public String serialize(HttpPartType type, HttpPartSchema schema, Object 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 5f3df96..1230f44 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,10 +13,13 @@
 package org.apache.juneau.httppart;
 
 /**
- * Represents possible enum values that can be passed to the {@link HttpPartSerializer#serialize(HttpPartType, Object)}.
+ * Represents possible enum values that can be passed to the {@link HttpPartSerializer#serialize(HttpPartType, HttpPartSchema, Object)}.
  */
 public enum HttpPartType {
 
+	/** An HTTP request body */
+	BODY,
+
 	/** A URI path variable */
 	PATH,
 
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 c7be584..842ae54 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
@@ -55,7 +55,7 @@ public class SimplePartParser implements HttpPartParser {
 	//-------------------------------------------------------------------------------------------------------------------
 
 	@Override
-	public <T> T parse(HttpPartType partType, String in, ClassMeta<T> type) throws ParseException {
+	public <T> T parse(HttpPartType partType, HttpPartSchema schema, String in, ClassMeta<T> type) throws ParseException {
 		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 31f3316..c10f1c9 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
@@ -35,7 +35,7 @@ public class SimplePartSerializer implements HttpPartSerializer {
 	//-------------------------------------------------------------------------------------------------------------------
 
 	@Override /* PartSerializer */
-	public String serialize(HttpPartType type, Object value) {
+	public String serialize(HttpPartType type, HttpPartSchema schema, Object value) {
 		return ClassUtils.toString(value);
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/oapi/OapiPartParser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/oapi/OapiPartParser.java
new file mode 100644
index 0000000..d76e1be
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/oapi/OapiPartParser.java
@@ -0,0 +1,247 @@
+// ***************************************************************************************************************************
+// * 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.oapi;
+
+import static org.apache.juneau.internal.StringUtils.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.uon.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.parser.*;
+
+/**
+ * OpenAPI part parser.
+ */
+public class OapiPartParser extends UonPartParser {
+
+	//-------------------------------------------------------------------------------------------------------------------
+	// Configurable properties
+	//-------------------------------------------------------------------------------------------------------------------
+
+	private static final String PREFIX = "OapiPartParser.";
+
+	/**
+	 * Configuration property:  OpenAPI schema description.
+	 * 
+	 * <h5 class='section'>Property:</h5>
+	 * <ul>
+	 * 	<li><b>Name:</b>  <js>"OapiPartParser.schema"</js>
+	 * 	<li><b>Data type:</b>  <code>HttpPartSchema</code>
+	 * 	<li><b>Default:</b>  <jk>false</jk>
+	 * 	<li><b>Session-overridable:</b>  <jk>false</jk>
+	 * 	<li><b>Methods:</b> 
+	 * 		<ul>
+	 * 			<li class='jm'>{@link OapiPartParserBuilder#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 OapiPartParser}. */
+	public static final OapiPartParser DEFAULT = new OapiPartParser(PropertyStore.DEFAULT);
+
+
+	//-------------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-------------------------------------------------------------------------------------------------------------------
+
+	final HttpPartSchema schema;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param ps The property store containing all the settings for this object.
+	 */
+	public OapiPartParser(PropertyStore ps) {
+		super(
+			ps.builder().build()
+		);
+		this.schema = getProperty(OAPI_schema, HttpPartSchema.class, HttpPartSchema.DEFAULT);
+	}
+
+	@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();
+	}
+
+	@Override /* HttpPartParser */
+	public <T> T parse(HttpPartType partType, HttpPartSchema schema, String in, ClassMeta<T> type) throws ParseException {
+		schema = ObjectUtils.firstNonNull(schema, this.schema, HttpPartSchema.DEFAULT);
+		T t = parseInner(partType, schema, in, type);
+		if (t == null && type.isPrimitive())
+			t = type.getPrimitiveDefault();
+		schema.validateOutput(t, this);
+		return t;
+	}
+	
+	@SuppressWarnings({ "unchecked" })
+	private<T> T parseInner(HttpPartType partType, HttpPartSchema schema, String in, ClassMeta<T> type) throws ParseException {
+		schema.validateInput(in);
+		if (in == null) {
+			if (schema.getDefault() == null)
+				return null;
+			in = schema.getDefault();
+		} else {
+			switch (schema.getType(type)) {
+				case STRING: {
+					if (type.isObject()) {
+						switch (schema.getFormat()) {
+							case BYTE: 
+								return (T)StringUtils.base64Decode(in);
+							case DATE: 
+							case DATE_TIME: 
+								return (T)StringUtils.parseIsoDate(in);
+							case BINARY: 
+								return (T)StringUtils.fromHex(in);
+							case UON: 
+								return super.parse(partType, schema, in, type);
+							default: 
+								return (T)in;
+						}
+					} 
+					switch (schema.getFormat()) {
+						case BYTE: 
+							return toType(StringUtils.base64Decode(in), type);
+						case DATE: 
+						case DATE_TIME: 
+							return toType(StringUtils.parseIsoDate(in), type);
+						case BINARY: 
+							return toType(StringUtils.fromHex(in), type);
+						case UON: 
+							return super.parse(partType, schema, in, type);
+						default: 
+							return toType(in, type);
+					}
+				}
+				case ARRAY: {
+					if (type.isObject()) 
+						type = (ClassMeta<T>)getClassMeta(ObjectList.class);
+					
+					ClassMeta<?> eType = type.isObject() ? string() : type.getElementType();
+					if (eType == null)
+						throw new ParseException("Value of type ARRAY cannot be converted to type {0}", type);
+					
+					String[] ss = new String[0];
+					switch (schema.getCollectionFormat()) {
+						case MULTI: 
+							ss = new String[]{in};
+							break;
+						case CSV: 
+							ss = split(in, ',');
+							break;
+						case PIPES: 
+							ss = split(in, '|');
+							break;
+						case SSV:
+							ss = splitQuoted(in);
+							break;
+						case TSV: 
+							ss = split(in, '\t');
+							break;
+						case UON: 
+							return super.parse(partType, null, in, type);
+						case NONE:
+							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;
+					}
+					return toType(o, type);
+				}
+				case BOOLEAN: {
+					if (type.isObject())
+						type = (ClassMeta<T>)getClassMeta(Boolean.class);
+					return super.parse(partType, schema, in, type);
+				}
+				case INTEGER: {
+					if (type.isObject()) {
+						switch (schema.getFormat()) {
+							case INT64:
+								type = (ClassMeta<T>)getClassMeta(Long.class);
+								break;
+							default:
+								type = (ClassMeta<T>)getClassMeta(Integer.class);
+								
+						}
+					}
+					return super.parse(partType, schema, in, type);
+				}
+				case NUMBER: {
+					if (type.isObject()) {
+						switch (schema.getFormat()) {
+							case DOUBLE:
+								type = (ClassMeta<T>)getClassMeta(Double.class);
+								break;
+							default:
+								type = (ClassMeta<T>)getClassMeta(Float.class);
+						}
+					}
+					return super.parse(partType, schema, in, type);
+				}
+				case OBJECT: {
+					if (type.isObject()) 
+						type = (ClassMeta<T>)getClassMeta(ObjectMap.class);
+					switch (schema.getFormat()) {
+						default:
+							return super.parse(partType, schema, in, type);
+					}
+				}
+				case FILE: {
+					throw new ParseException("File part not supported.");
+				}
+				case NONE: {
+					throw new ParseException("Invalid type.");
+				}
+			}
+		}
+		
+		return super.parse(partType, schema, in, type);
+	}
+	
+	private <T> T toType(Object in, ClassMeta<T> type) {
+		return createBeanSession().convertToType(in, type);
+	}
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartParserBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/oapi/OapiPartParserBuilder.java
similarity index 59%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartParserBuilder.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/oapi/OapiPartParserBuilder.java
index 9110e0d..0c100ba 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartParserBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/oapi/OapiPartParserBuilder.java
@@ -10,26 +10,29 @@
 // * "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;
+package org.apache.juneau.httppart.oapi;
 
-import static org.apache.juneau.uon.UonParser.*;
+import static org.apache.juneau.httppart.oapi.OapiPartParser.*;
 
 import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.*;
+import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.uon.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.uon.*;
+import org.apache.juneau.urlencoding.*;
 
 /**
- * Builder class for building instances of {@link UonPartParser}.
+ * Builder class for building instances of {@link OapiPartParser}.
  */
-public class UonPartParserBuilder extends UonParserBuilder {
+public class OapiPartParserBuilder extends UonPartParserBuilder {
 
 	/**
 	 * Constructor, default settings.
 	 */
-	public UonPartParserBuilder() {
+	public OapiPartParserBuilder() {
 		super();
 	}
 
@@ -38,13 +41,13 @@ public class UonPartParserBuilder extends UonParserBuilder {
 	 * 
 	 * @param ps The initial configuration settings for this builder.
 	 */
-	public UonPartParserBuilder(PropertyStore ps) {
+	public OapiPartParserBuilder(PropertyStore ps) {
 		super(ps);
 	}
 
 	@Override /* ContextBuilder */
-	public UonPartParser build() {
-		return build(UonPartParser.class);
+	public OapiPartParser build() {
+		return build(OapiPartParser.class);
 	}
 
 
@@ -52,427 +55,448 @@ public class UonPartParserBuilder extends UonParserBuilder {
 	// Properties
 	//--------------------------------------------------------------------------------
 
+	/**
+	 * Configuration property: Decode <js>"%xx"</js> sequences.
+	 * 
+	 * <p>
+	 * Specify <jk>true</jk> if URI encoded characters should be decoded, <jk>false</jk> if they've already been
+	 * decoded before being passed to this parser.
+	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='jf'>{@link UonParser#UON_decoding}
+	 * </ul>
+	 * 
+	 * @param value 
+	 * 	The new value for this property.
+	 * 	<br>Default is <jk>false</jk> for {@link UonParser}, <jk>true</jk> for {@link UrlEncodingParser}
+	 * @return This object (for method chaining).
+	 */
+	public OapiPartParserBuilder schema(HttpPartSchema value) {
+		return set(OAPI_schema, value);
+	}
+
 	@Override /* UonParserBuilder */
-	public UonPartParserBuilder decoding(boolean value) {
+	public OapiPartParserBuilder decoding(boolean value) {
 		return set(UON_decoding, value);
 	}
 
 	@Override /* ParserBuilder */
-	public UonPartParserBuilder fileCharset(String value) {
+	public OapiPartParserBuilder fileCharset(String value) {
 		super.fileCharset(value);
 		return this;
 	}
 
 	@Override /* ParserBuilder */
-	public UonPartParserBuilder inputStreamCharset(String value) {
+	public OapiPartParserBuilder inputStreamCharset(String value) {
 		super.inputStreamCharset(value);
 		return this;
 	}
 
 	@Override /* ParserBuilder */
-	public UonPartParserBuilder listener(Class<? extends ParserListener> value) {
+	public OapiPartParserBuilder listener(Class<? extends ParserListener> value) {
 		super.listener(value);
 		return this;
 	}
 
 	@Override /* ParserBuilder */
-	public UonPartParserBuilder strict(boolean value) {
+	public OapiPartParserBuilder strict(boolean value) {
 		super.strict(value);
 		return this;
 	}
 
 	@Override /* ParserBuilder */
-	public UonPartParserBuilder strict() {
+	public OapiPartParserBuilder strict() {
 		super.strict();
 		return this;
 	}
 
 	@Override /* ParserBuilder */
-	public UonPartParserBuilder trimStrings(boolean value) {
+	public OapiPartParserBuilder trimStrings(boolean value) {
 		super.trimStrings(value);
 		return this;
 	}
 
 	@Override /* ParserBuilder */
-	public UonPartParserBuilder trimStrings() {
+	public OapiPartParserBuilder trimStrings() {
 		super.trimStrings();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beanClassVisibility(Visibility value) {
+	public OapiPartParserBuilder beanClassVisibility(Visibility value) {
 		super.beanClassVisibility(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beanConstructorVisibility(Visibility value) {
+	public OapiPartParserBuilder beanConstructorVisibility(Visibility value) {
 		super.beanConstructorVisibility(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beanDictionary(boolean append, Object...values) {
+	public OapiPartParserBuilder beanDictionary(boolean append, Object...values) {
 		super.beanDictionary(append, values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beanDictionary(Class<?>...values) {
+	public OapiPartParserBuilder beanDictionary(Class<?>...values) {
 		super.beanDictionary(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beanDictionary(Object...values) {
+	public OapiPartParserBuilder beanDictionary(Object...values) {
 		super.beanDictionary(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beanDictionaryRemove(Object...values) {
+	public OapiPartParserBuilder beanDictionaryRemove(Object...values) {
 		super.beanDictionaryRemove(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beanFieldVisibility(Visibility value) {
+	public OapiPartParserBuilder beanFieldVisibility(Visibility value) {
 		super.beanFieldVisibility(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beanFilters(boolean append, Object...values) {
+	public OapiPartParserBuilder beanFilters(boolean append, Object...values) {
 		super.beanFilters(append, values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beanFilters(Class<?>...values) {
+	public OapiPartParserBuilder beanFilters(Class<?>...values) {
 		super.beanFilters(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beanFilters(Object...values) {
+	public OapiPartParserBuilder beanFilters(Object...values) {
 		super.beanFilters(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beanFiltersRemove(Object...values) {
+	public OapiPartParserBuilder beanFiltersRemove(Object...values) {
 		super.beanFiltersRemove(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beanMapPutReturnsOldValue(boolean value) {
+	public OapiPartParserBuilder beanMapPutReturnsOldValue(boolean value) {
 		super.beanMapPutReturnsOldValue(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beanMapPutReturnsOldValue() {
+	public OapiPartParserBuilder beanMapPutReturnsOldValue() {
 		super.beanMapPutReturnsOldValue();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beanMethodVisibility(Visibility value) {
+	public OapiPartParserBuilder beanMethodVisibility(Visibility value) {
 		super.beanMethodVisibility(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beansRequireDefaultConstructor(boolean value) {
+	public OapiPartParserBuilder beansRequireDefaultConstructor(boolean value) {
 		super.beansRequireDefaultConstructor(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beansRequireDefaultConstructor() {
+	public OapiPartParserBuilder beansRequireDefaultConstructor() {
 		super.beansRequireDefaultConstructor();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beansRequireSerializable(boolean value) {
+	public OapiPartParserBuilder beansRequireSerializable(boolean value) {
 		super.beansRequireSerializable(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beansRequireSerializable() {
+	public OapiPartParserBuilder beansRequireSerializable() {
 		super.beansRequireSerializable();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beansRequireSettersForGetters(boolean value) {
+	public OapiPartParserBuilder beansRequireSettersForGetters(boolean value) {
 		super.beansRequireSettersForGetters(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beansRequireSettersForGetters() {
+	public OapiPartParserBuilder beansRequireSettersForGetters() {
 		super.beansRequireSettersForGetters();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beansRequireSomeProperties(boolean value) {
+	public OapiPartParserBuilder beansRequireSomeProperties(boolean value) {
 		super.beansRequireSomeProperties(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder beanTypePropertyName(String value) {
+	public OapiPartParserBuilder beanTypePropertyName(String value) {
 		super.beanTypePropertyName(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder debug() {
+	public OapiPartParserBuilder debug() {
 		super.debug();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public <T> UonPartParserBuilder example(Class<T> c, T o) {
+	public <T> OapiPartParserBuilder example(Class<T> c, T o) {
 		super.example(c, o);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder ignoreInvocationExceptionsOnGetters(boolean value) {
+	public OapiPartParserBuilder ignoreInvocationExceptionsOnGetters(boolean value) {
 		super.ignoreInvocationExceptionsOnGetters(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder ignoreInvocationExceptionsOnGetters() {
+	public OapiPartParserBuilder ignoreInvocationExceptionsOnGetters() {
 		super.ignoreInvocationExceptionsOnGetters();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder ignoreInvocationExceptionsOnSetters(boolean value) {
+	public OapiPartParserBuilder ignoreInvocationExceptionsOnSetters(boolean value) {
 		super.ignoreInvocationExceptionsOnSetters(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder ignoreInvocationExceptionsOnSetters() {
+	public OapiPartParserBuilder ignoreInvocationExceptionsOnSetters() {
 		super.ignoreInvocationExceptionsOnSetters();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder ignorePropertiesWithoutSetters(boolean value) {
+	public OapiPartParserBuilder ignorePropertiesWithoutSetters(boolean value) {
 		super.ignorePropertiesWithoutSetters(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder ignoreUnknownBeanProperties(boolean value) {
+	public OapiPartParserBuilder ignoreUnknownBeanProperties(boolean value) {
 		super.ignoreUnknownBeanProperties(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder ignoreUnknownBeanProperties() {
+	public OapiPartParserBuilder ignoreUnknownBeanProperties() {
 		super.ignoreUnknownBeanProperties();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder ignoreUnknownNullBeanProperties(boolean value) {
+	public OapiPartParserBuilder ignoreUnknownNullBeanProperties(boolean value) {
 		super.ignoreUnknownNullBeanProperties(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public <T> UonPartParserBuilder implClass(Class<T> interfaceClass, Class<? extends T> implClass) {
+	public <T> OapiPartParserBuilder implClass(Class<T> interfaceClass, Class<? extends T> implClass) {
 		super.implClass(interfaceClass, implClass);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder implClasses(Map<String,Class<?>> values) {
+	public OapiPartParserBuilder implClasses(Map<String,Class<?>> values) {
 		super.implClasses(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder locale(Locale value) {
+	public OapiPartParserBuilder locale(Locale value) {
 		super.locale(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder mediaType(MediaType value) {
+	public OapiPartParserBuilder mediaType(MediaType value) {
 		super.mediaType(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder notBeanClasses(boolean append, Object...values) {
+	public OapiPartParserBuilder notBeanClasses(boolean append, Object...values) {
 		super.notBeanClasses(append, values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder notBeanClasses(Class<?>...values) {
+	public OapiPartParserBuilder notBeanClasses(Class<?>...values) {
 		super.notBeanClasses(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder notBeanClasses(Object...values) {
+	public OapiPartParserBuilder notBeanClasses(Object...values) {
 		super.notBeanClasses(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder notBeanClassesRemove(Object...values) {
+	public OapiPartParserBuilder notBeanClassesRemove(Object...values) {
 		super.notBeanClassesRemove(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder notBeanPackages(boolean append, Object...values) {
+	public OapiPartParserBuilder notBeanPackages(boolean append, Object...values) {
 		super.notBeanPackages(append, values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder notBeanPackages(Object...values) {
+	public OapiPartParserBuilder notBeanPackages(Object...values) {
 		super.notBeanPackages(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder notBeanPackages(String...values) {
+	public OapiPartParserBuilder notBeanPackages(String...values) {
 		super.notBeanPackages(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder notBeanPackagesRemove(Object...values) {
+	public OapiPartParserBuilder notBeanPackagesRemove(Object...values) {
 		super.notBeanPackagesRemove(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder pojoSwaps(boolean append, Object...values) {
+	public OapiPartParserBuilder pojoSwaps(boolean append, Object...values) {
 		super.pojoSwaps(append, values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder pojoSwaps(Class<?>...values) {
+	public OapiPartParserBuilder pojoSwaps(Class<?>...values) {
 		super.pojoSwaps(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder pojoSwaps(Object...values) {
+	public OapiPartParserBuilder pojoSwaps(Object...values) {
 		super.pojoSwaps(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder pojoSwapsRemove(Object...values) {
+	public OapiPartParserBuilder pojoSwapsRemove(Object...values) {
 		super.pojoSwapsRemove(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder sortProperties(boolean value) {
+	public OapiPartParserBuilder sortProperties(boolean value) {
 		super.sortProperties(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder sortProperties() {
+	public OapiPartParserBuilder sortProperties() {
 		super.sortProperties();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder timeZone(TimeZone value) {
+	public OapiPartParserBuilder timeZone(TimeZone value) {
 		super.timeZone(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder useEnumNames() {
+	public OapiPartParserBuilder useEnumNames() {
 		super.useEnumNames();
 		return this;
 	}
 	
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder useInterfaceProxies(boolean value) {
+	public OapiPartParserBuilder useInterfaceProxies(boolean value) {
 		super.useInterfaceProxies(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder useJavaBeanIntrospector(boolean value) {
+	public OapiPartParserBuilder useJavaBeanIntrospector(boolean value) {
 		super.useJavaBeanIntrospector(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartParserBuilder useJavaBeanIntrospector() {
+	public OapiPartParserBuilder useJavaBeanIntrospector() {
 		super.useJavaBeanIntrospector();
 		return this;
 	}
 	
 	@Override /* ContextBuilder */
-	public UonPartParserBuilder set(String name, Object value) {
+	public OapiPartParserBuilder set(String name, Object value) {
 		super.set(name, value);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public UonPartParserBuilder set(boolean append, String name, Object value) {
+	public OapiPartParserBuilder set(boolean append, String name, Object value) {
 		super.set(append, name, value);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public UonPartParserBuilder set(Map<String,Object> properties) {
+	public OapiPartParserBuilder set(Map<String,Object> properties) {
 		super.set(properties);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public UonPartParserBuilder add(Map<String,Object> properties) {
+	public OapiPartParserBuilder add(Map<String,Object> properties) {
 		super.add(properties);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public UonPartParserBuilder addTo(String name, Object value) {
+	public OapiPartParserBuilder addTo(String name, Object value) {
 		super.addTo(name, value);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public UonPartParserBuilder addTo(String name, String key, Object value) {
+	public OapiPartParserBuilder addTo(String name, String key, Object value) {
 		super.addTo(name, key, value);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public UonPartParserBuilder removeFrom(String name, Object value) {
+	public OapiPartParserBuilder removeFrom(String name, Object value) {
 		super.removeFrom(name, value);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public UonPartParserBuilder apply(PropertyStore copyFrom) {
+	public OapiPartParserBuilder apply(PropertyStore copyFrom) {
 		super.apply(copyFrom);
 		return this;
 	}
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/oapi/OapiPartSerializer.java
similarity index 65%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartSerializer.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/oapi/OapiPartSerializer.java
index 0d9ed56..b449d94 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/oapi/OapiPartSerializer.java
@@ -10,13 +10,12 @@
 // * "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.*;
+package org.apache.juneau.httppart.oapi;
 
 import org.apache.juneau.*;
+import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.uon.*;
 import org.apache.juneau.internal.*;
-import org.apache.juneau.uon.*;
 
 /**
  * Serializes POJOs to values suitable for transmission as HTTP headers, query/form-data parameters, and path variables.
@@ -25,32 +24,63 @@ import org.apache.juneau.uon.*;
  * 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.
  */
-public class UonPartSerializer extends UonSerializer implements HttpPartSerializer {
+public class OapiPartSerializer extends UonPartSerializer {
+
+	//-------------------------------------------------------------------------------------------------------------------
+	// Configurable properties
+	//-------------------------------------------------------------------------------------------------------------------
+
+	private static final String PREFIX = "OapiPartSerializer.";
+
+	/**
+	 * Configuration property:  OpenAPI schema description.
+	 * 
+	 * <h5 class='section'>Property:</h5>
+	 * <ul>
+	 * 	<li><b>Name:</b>  <js>"OapiPartSerializer.schema"</js>
+	 * 	<li><b>Data type:</b>  <code>HttpPartSchema</code>
+	 * 	<li><b>Default:</b>  <jk>false</jk>
+	 * 	<li><b>Session-overridable:</b>  <jk>false</jk>
+	 * 	<li><b>Methods:</b> 
+	 * 		<ul>
+	 * 			<li class='jm'>{@link OapiPartSerializerBuilder#schema(HttpPartSchema)}
+	 * 		</ul>
+	 * </ul>
+	 * 
+	 * <h5 class='section'>Description:</h5>
+	 * <p>
+	 * Defines the OpenAPI schema for this part serializer.
+	 */
+	public static final String OAPI_schema = PREFIX + "schema.o";
+
 
 	//-------------------------------------------------------------------------------------------------------------------
 	// Predefined instances
 	//-------------------------------------------------------------------------------------------------------------------
 
-	/** Reusable instance of {@link UonPartSerializer}, all default settings. */
-	public static final UonPartSerializer DEFAULT = new UonPartSerializer(PropertyStore.DEFAULT);
+	/** Reusable instance of {@link OapiPartSerializer}, all default settings. */
+	public static final OapiPartSerializer DEFAULT = new OapiPartSerializer(PropertyStore.DEFAULT);
 
 
 	//-------------------------------------------------------------------------------------------------------------------
 	// Instance
 	//-------------------------------------------------------------------------------------------------------------------
 
+	final HttpPartSchema schema;
+
 	/**
 	 * Constructor.
 	 * 
 	 * @param ps
 	 * 	The property store containing all the settings for this object.
 	 */
-	public UonPartSerializer(PropertyStore ps) {
+	public OapiPartSerializer(PropertyStore ps) {
 		super(
 			ps.builder()
 				.set(UON_encoding, false)
 				.build() 
 		);
+		this.schema = getProperty(OAPI_schema, HttpPartSchema.class, HttpPartSchema.DEFAULT);
 	}
 
 	@Override /* Context */
@@ -76,25 +106,8 @@ public class UonPartSerializer extends UonSerializer implements HttpPartSerializ
 	//--------------------------------------------------------------------------------
 
 	@Override /* PartSerializer */
-	public String serialize(HttpPartType type, Object value) {
-		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);
-		}
+	public String serialize(HttpPartType type, HttpPartSchema schema, Object value) {
+		schema = ObjectUtils.firstNonNull(schema, this.schema, HttpPartSchema.DEFAULT);
+		return super.serialize(type, schema, value);
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartSerializerBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/oapi/OapiPartSerializerBuilder.java
similarity index 58%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartSerializerBuilder.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/oapi/OapiPartSerializerBuilder.java
index c26cbf8..7d232ab 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartSerializerBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/oapi/OapiPartSerializerBuilder.java
@@ -10,24 +10,29 @@
 // * "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;
+package org.apache.juneau.httppart.oapi;
+
+import static org.apache.juneau.httppart.oapi.OapiPartSerializer.*;
 
 import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.*;
+import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.uon.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.uon.*;
+import org.apache.juneau.urlencoding.*;
 
 /**
  * Builder class for building instances of {@link UonPartSerializer}.
  */
-public class UonPartSerializerBuilder extends UonSerializerBuilder {
+public class OapiPartSerializerBuilder extends UonPartSerializerBuilder {
 
 	/**
 	 * Constructor, default settings.
 	 */
-	public UonPartSerializerBuilder() {
+	public OapiPartSerializerBuilder() {
 		super();
 	}
 
@@ -36,13 +41,13 @@ public class UonPartSerializerBuilder extends UonSerializerBuilder {
 	 * 
 	 * @param ps The initial configuration settings for this builder.
 	 */
-	public UonPartSerializerBuilder(PropertyStore ps) {
+	public OapiPartSerializerBuilder(PropertyStore ps) {
 		super(ps);
 	}
 
 	@Override /* ContextBuilder */
-	public UonPartSerializer build() {
-		return build(UonPartSerializer.class);
+	public OapiPartSerializer build() {
+		return build(OapiPartSerializer.class);
 	}
 
 
@@ -50,565 +55,586 @@ public class UonPartSerializerBuilder extends UonSerializerBuilder {
 	// Properties
 	//--------------------------------------------------------------------------------
 
+	/**
+	 * Configuration property: Decode <js>"%xx"</js> sequences.
+	 * 
+	 * <p>
+	 * Specify <jk>true</jk> if URI encoded characters should be decoded, <jk>false</jk> if they've already been
+	 * decoded before being passed to this parser.
+	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='jf'>{@link UonParser#UON_decoding}
+	 * </ul>
+	 * 
+	 * @param value 
+	 * 	The new value for this property.
+	 * 	<br>Default is <jk>false</jk> for {@link UonParser}, <jk>true</jk> for {@link UrlEncodingParser}
+	 * @return This object (for method chaining).
+	 */
+	public OapiPartSerializerBuilder schema(HttpPartSchema value) {
+		return set(OAPI_schema, value);
+	}
+
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder addBeanTypes(boolean value) {
+	public OapiPartSerializerBuilder addBeanTypes(boolean value) {
 		super.addBeanTypes(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder addBeanTypes() {
+	public OapiPartSerializerBuilder addBeanTypes() {
 		super.addBeanTypes();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder addRootType(boolean value) {
+	public OapiPartSerializerBuilder addRootType(boolean value) {
 		super.addRootType(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder addRootType() {
+	public OapiPartSerializerBuilder addRootType() {
 		super.addRootType();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder detectRecursions(boolean value) {
+	public OapiPartSerializerBuilder detectRecursions(boolean value) {
 		super.detectRecursions(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder detectRecursions() {
+	public OapiPartSerializerBuilder detectRecursions() {
 		super.detectRecursions();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder ignoreRecursions(boolean value) {
+	public OapiPartSerializerBuilder ignoreRecursions(boolean value) {
 		super.ignoreRecursions(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder ignoreRecursions() {
+	public OapiPartSerializerBuilder ignoreRecursions() {
 		super.ignoreRecursions();
 		return this;
 	}
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder initialDepth(int value) {
+	public OapiPartSerializerBuilder initialDepth(int value) {
 		super.initialDepth(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder listener(Class<? extends SerializerListener> value) {
+	public OapiPartSerializerBuilder listener(Class<? extends SerializerListener> value) {
 		super.listener(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder maxDepth(int value) {
+	public OapiPartSerializerBuilder maxDepth(int value) {
 		super.maxDepth(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder maxIndent(int value) {
+	public OapiPartSerializerBuilder maxIndent(int value) {
 		super.maxIndent(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder quoteChar(char value) {
+	public OapiPartSerializerBuilder quoteChar(char value) {
 		super.quoteChar(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder sortCollections(boolean value) {
+	public OapiPartSerializerBuilder sortCollections(boolean value) {
 		super.sortCollections(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder sortCollections() {
+	public OapiPartSerializerBuilder sortCollections() {
 		super.sortCollections();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder sortMaps(boolean value) {
+	public OapiPartSerializerBuilder sortMaps(boolean value) {
 		super.sortMaps(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder sortMaps() {
+	public OapiPartSerializerBuilder sortMaps() {
 		super.sortMaps();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder sq() {
+	public OapiPartSerializerBuilder sq() {
 		super.sq();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder trimEmptyCollections(boolean value) {
+	public OapiPartSerializerBuilder trimEmptyCollections(boolean value) {
 		super.trimEmptyCollections(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder trimEmptyCollections() {
+	public OapiPartSerializerBuilder trimEmptyCollections() {
 		super.trimEmptyCollections();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder trimEmptyMaps(boolean value) {
+	public OapiPartSerializerBuilder trimEmptyMaps(boolean value) {
 		super.trimEmptyMaps(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder trimEmptyMaps() {
+	public OapiPartSerializerBuilder trimEmptyMaps() {
 		super.trimEmptyMaps();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder trimNullProperties(boolean value) {
+	public OapiPartSerializerBuilder trimNullProperties(boolean value) {
 		super.trimNullProperties(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder trimStrings(boolean value) {
+	public OapiPartSerializerBuilder trimStrings(boolean value) {
 		super.trimStrings(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder trimStrings() {
+	public OapiPartSerializerBuilder trimStrings() {
 		super.trimStrings();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder uriContext(UriContext value) {
+	public OapiPartSerializerBuilder uriContext(UriContext value) {
 		super.uriContext(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder uriRelativity(UriRelativity value) {
+	public OapiPartSerializerBuilder uriRelativity(UriRelativity value) {
 		super.uriRelativity(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder uriResolution(UriResolution value) {
+	public OapiPartSerializerBuilder uriResolution(UriResolution value) {
 		super.uriResolution(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder useWhitespace(boolean value) {
+	public OapiPartSerializerBuilder useWhitespace(boolean value) {
 		super.useWhitespace(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder useWhitespace() {
+	public OapiPartSerializerBuilder useWhitespace() {
 		super.useWhitespace();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public UonPartSerializerBuilder ws() {
+	public OapiPartSerializerBuilder ws() {
 		super.ws();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beanClassVisibility(Visibility value) {
+	public OapiPartSerializerBuilder beanClassVisibility(Visibility value) {
 		super.beanClassVisibility(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beanConstructorVisibility(Visibility value) {
+	public OapiPartSerializerBuilder beanConstructorVisibility(Visibility value) {
 		super.beanConstructorVisibility(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beanDictionary(boolean append, Object...values) {
+	public OapiPartSerializerBuilder beanDictionary(boolean append, Object...values) {
 		super.beanDictionary(append, values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beanDictionary(Class<?>...values) {
+	public OapiPartSerializerBuilder beanDictionary(Class<?>...values) {
 		super.beanDictionary(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beanDictionary(Object...values) {
+	public OapiPartSerializerBuilder beanDictionary(Object...values) {
 		super.beanDictionary(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beanDictionaryRemove(Object...values) {
+	public OapiPartSerializerBuilder beanDictionaryRemove(Object...values) {
 		super.beanDictionaryRemove(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beanFieldVisibility(Visibility value) {
+	public OapiPartSerializerBuilder beanFieldVisibility(Visibility value) {
 		super.beanFieldVisibility(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beanFilters(boolean append, Object...values) {
+	public OapiPartSerializerBuilder beanFilters(boolean append, Object...values) {
 		super.beanFilters(append, values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beanFilters(Class<?>...values) {
+	public OapiPartSerializerBuilder beanFilters(Class<?>...values) {
 		super.beanFilters(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beanFilters(Object...values) {
+	public OapiPartSerializerBuilder beanFilters(Object...values) {
 		super.beanFilters(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beanFiltersRemove(Object...values) {
+	public OapiPartSerializerBuilder beanFiltersRemove(Object...values) {
 		super.beanFiltersRemove(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beanMapPutReturnsOldValue(boolean value) {
+	public OapiPartSerializerBuilder beanMapPutReturnsOldValue(boolean value) {
 		super.beanMapPutReturnsOldValue(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beanMapPutReturnsOldValue() {
+	public OapiPartSerializerBuilder beanMapPutReturnsOldValue() {
 		super.beanMapPutReturnsOldValue();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beanMethodVisibility(Visibility value) {
+	public OapiPartSerializerBuilder beanMethodVisibility(Visibility value) {
 		super.beanMethodVisibility(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beansRequireDefaultConstructor(boolean value) {
+	public OapiPartSerializerBuilder beansRequireDefaultConstructor(boolean value) {
 		super.beansRequireDefaultConstructor(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beansRequireDefaultConstructor() {
+	public OapiPartSerializerBuilder beansRequireDefaultConstructor() {
 		super.beansRequireDefaultConstructor();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beansRequireSerializable(boolean value) {
+	public OapiPartSerializerBuilder beansRequireSerializable(boolean value) {
 		super.beansRequireSerializable(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beansRequireSerializable() {
+	public OapiPartSerializerBuilder beansRequireSerializable() {
 		super.beansRequireSerializable();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beansRequireSettersForGetters(boolean value) {
+	public OapiPartSerializerBuilder beansRequireSettersForGetters(boolean value) {
 		super.beansRequireSettersForGetters(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beansRequireSettersForGetters() {
+	public OapiPartSerializerBuilder beansRequireSettersForGetters() {
 		super.beansRequireSettersForGetters();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beansRequireSomeProperties(boolean value) {
+	public OapiPartSerializerBuilder beansRequireSomeProperties(boolean value) {
 		super.beansRequireSomeProperties(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder beanTypePropertyName(String value) {
+	public OapiPartSerializerBuilder beanTypePropertyName(String value) {
 		super.beanTypePropertyName(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder debug() {
+	public OapiPartSerializerBuilder debug() {
 		super.debug();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public <T> UonPartSerializerBuilder example(Class<T> c, T o) {
+	public <T> OapiPartSerializerBuilder example(Class<T> c, T o) {
 		super.example(c, o);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder ignoreInvocationExceptionsOnGetters(boolean value) {
+	public OapiPartSerializerBuilder ignoreInvocationExceptionsOnGetters(boolean value) {
 		super.ignoreInvocationExceptionsOnGetters(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder ignoreInvocationExceptionsOnGetters() {
+	public OapiPartSerializerBuilder ignoreInvocationExceptionsOnGetters() {
 		super.ignoreInvocationExceptionsOnGetters();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder ignoreInvocationExceptionsOnSetters(boolean value) {
+	public OapiPartSerializerBuilder ignoreInvocationExceptionsOnSetters(boolean value) {
 		super.ignoreInvocationExceptionsOnSetters(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder ignoreInvocationExceptionsOnSetters() {
+	public OapiPartSerializerBuilder ignoreInvocationExceptionsOnSetters() {
 		super.ignoreInvocationExceptionsOnSetters();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder ignorePropertiesWithoutSetters(boolean value) {
+	public OapiPartSerializerBuilder ignorePropertiesWithoutSetters(boolean value) {
 		super.ignorePropertiesWithoutSetters(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder ignoreUnknownBeanProperties(boolean value) {
+	public OapiPartSerializerBuilder ignoreUnknownBeanProperties(boolean value) {
 		super.ignoreUnknownBeanProperties(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder ignoreUnknownBeanProperties() {
+	public OapiPartSerializerBuilder ignoreUnknownBeanProperties() {
 		super.ignoreUnknownBeanProperties();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder ignoreUnknownNullBeanProperties(boolean value) {
+	public OapiPartSerializerBuilder ignoreUnknownNullBeanProperties(boolean value) {
 		super.ignoreUnknownNullBeanProperties(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public <T> UonPartSerializerBuilder implClass(Class<T> interfaceClass, Class<? extends T> implClass) {
+	public <T> OapiPartSerializerBuilder implClass(Class<T> interfaceClass, Class<? extends T> implClass) {
 		super.implClass(interfaceClass, implClass);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder implClasses(Map<String,Class<?>> values) {
+	public OapiPartSerializerBuilder implClasses(Map<String,Class<?>> values) {
 		super.implClasses(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder locale(Locale value) {
+	public OapiPartSerializerBuilder locale(Locale value) {
 		super.locale(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder mediaType(MediaType value) {
+	public OapiPartSerializerBuilder mediaType(MediaType value) {
 		super.mediaType(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder notBeanClasses(boolean append, Object...values) {
+	public OapiPartSerializerBuilder notBeanClasses(boolean append, Object...values) {
 		super.notBeanClasses(append, values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder notBeanClasses(Class<?>...values) {
+	public OapiPartSerializerBuilder notBeanClasses(Class<?>...values) {
 		super.notBeanClasses(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder notBeanClasses(Object...values) {
+	public OapiPartSerializerBuilder notBeanClasses(Object...values) {
 		super.notBeanClasses(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder notBeanClassesRemove(Object...values) {
+	public OapiPartSerializerBuilder notBeanClassesRemove(Object...values) {
 		super.notBeanClassesRemove(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder notBeanPackages(boolean append, Object...values) {
+	public OapiPartSerializerBuilder notBeanPackages(boolean append, Object...values) {
 		super.notBeanPackages(append, values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder notBeanPackages(Object...values) {
+	public OapiPartSerializerBuilder notBeanPackages(Object...values) {
 		super.notBeanPackages(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder notBeanPackages(String...values) {
+	public OapiPartSerializerBuilder notBeanPackages(String...values) {
 		super.notBeanPackages(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder notBeanPackagesRemove(Object...values) {
+	public OapiPartSerializerBuilder notBeanPackagesRemove(Object...values) {
 		super.notBeanPackagesRemove(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder pojoSwaps(boolean append, Object...values) {
+	public OapiPartSerializerBuilder pojoSwaps(boolean append, Object...values) {
 		super.pojoSwaps(append, values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder pojoSwaps(Class<?>...values) {
+	public OapiPartSerializerBuilder pojoSwaps(Class<?>...values) {
 		super.pojoSwaps(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder pojoSwaps(Object...values) {
+	public OapiPartSerializerBuilder pojoSwaps(Object...values) {
 		super.pojoSwaps(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder pojoSwapsRemove(Object...values) {
+	public OapiPartSerializerBuilder pojoSwapsRemove(Object...values) {
 		super.pojoSwapsRemove(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder sortProperties(boolean value) {
+	public OapiPartSerializerBuilder sortProperties(boolean value) {
 		super.sortProperties(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder sortProperties() {
+	public OapiPartSerializerBuilder sortProperties() {
 		super.sortProperties();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder timeZone(TimeZone value) {
+	public OapiPartSerializerBuilder timeZone(TimeZone value) {
 		super.timeZone(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder useEnumNames() {
+	public OapiPartSerializerBuilder useEnumNames() {
 		super.useEnumNames();
 		return this;
 	}
 	
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder useInterfaceProxies(boolean value) {
+	public OapiPartSerializerBuilder useInterfaceProxies(boolean value) {
 		super.useInterfaceProxies(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder useJavaBeanIntrospector(boolean value) {
+	public OapiPartSerializerBuilder useJavaBeanIntrospector(boolean value) {
 		super.useJavaBeanIntrospector(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public UonPartSerializerBuilder useJavaBeanIntrospector() {
+	public OapiPartSerializerBuilder useJavaBeanIntrospector() {
 		super.useJavaBeanIntrospector();
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public UonSerializerBuilder set(String name, Object value) {
+	public OapiPartSerializerBuilder set(String name, Object value) {
 		super.set(name, value);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public UonPartSerializerBuilder set(boolean append, String name, Object value) {
+	public OapiPartSerializerBuilder set(boolean append, String name, Object value) {
 		super.set(append, name, value);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public UonPartSerializerBuilder set(Map<String,Object> properties) {
+	public OapiPartSerializerBuilder set(Map<String,Object> properties) {
 		super.set(properties);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public UonPartSerializerBuilder add(Map<String,Object> properties) {
+	public OapiPartSerializerBuilder add(Map<String,Object> properties) {
 		super.add(properties);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public UonPartSerializerBuilder addTo(String name, Object value) {
+	public OapiPartSerializerBuilder addTo(String name, Object value) {
 		super.addTo(name, value);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public UonPartSerializerBuilder addTo(String name, String key, Object value) {
+	public OapiPartSerializerBuilder addTo(String name, String key, Object value) {
 		super.addTo(name, key, value);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public UonPartSerializerBuilder removeFrom(String name, Object value) {
+	public OapiPartSerializerBuilder removeFrom(String name, Object value) {
 		super.removeFrom(name, value);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public UonPartSerializerBuilder apply(PropertyStore copyFrom) {
+	public OapiPartSerializerBuilder apply(PropertyStore copyFrom) {
 		super.apply(copyFrom);
 		return this;
 	}
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/uon/SimpleUonPartSerializer.java
similarity index 97%
rename from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimpleUonPartSerializer.java
rename to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/uon/SimpleUonPartSerializer.java
index b69b16f..6924723 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/uon/SimpleUonPartSerializer.java
@@ -10,7 +10,7 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.httppart;
+package org.apache.juneau.httppart.uon;
 
 import org.apache.juneau.*;
 import org.apache.juneau.uon.*;
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimpleUonPartSerializerBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/uon/SimpleUonPartSerializerBuilder.java
similarity index 99%
rename from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimpleUonPartSerializerBuilder.java
rename to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/uon/SimpleUonPartSerializerBuilder.java
index 9ee32d7..40be466 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimpleUonPartSerializerBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/uon/SimpleUonPartSerializerBuilder.java
@@ -10,7 +10,7 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.httppart;
+package org.apache.juneau.httppart.uon;
 
 import java.util.*;
 
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/uon/UonPartParser.java
similarity index 87%
rename from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartParser.java
rename to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/uon/UonPartParser.java
index ec8d320..0f674ec 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/uon/UonPartParser.java
@@ -10,11 +10,12 @@
 // * "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;
+package org.apache.juneau.httppart.uon;
 
 import static org.apache.juneau.internal.StringUtils.*;
 
 import org.apache.juneau.*;
+import org.apache.juneau.httppart.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.uon.*;
 
@@ -73,9 +74,21 @@ public class UonPartParser extends UonParser implements HttpPartParser {
 		return new UonPartParserBuilder();
 	}
 
-
-	@Override /* HttpPartParser */
+	/**
+	 * 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
+	 */
 	public <T> T parse(HttpPartType partType, String in, ClassMeta<T> type) throws ParseException {
+		return parse(partType, null, in, type);
+	}
+	
+	@Override /* HttpPartParser */
+	public <T> T parse(HttpPartType partType, HttpPartSchema schema, String in, ClassMeta<T> type) throws ParseException {
 		if (in == null)
 			return null;
 		if (type.isString() && in.length() > 0) {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartParserBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/uon/UonPartParserBuilder.java
similarity index 99%
rename from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartParserBuilder.java
rename to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/uon/UonPartParserBuilder.java
index 9110e0d..7f0c67b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartParserBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/uon/UonPartParserBuilder.java
@@ -10,7 +10,7 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.httppart;
+package org.apache.juneau.httppart.uon;
 
 import static org.apache.juneau.uon.UonParser.*;
 
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/uon/UonPartSerializer.java
similarity index 88%
rename from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartSerializer.java
rename to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/uon/UonPartSerializer.java
index 0d9ed56..96657bc 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/uon/UonPartSerializer.java
@@ -10,11 +10,12 @@
 // * "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;
+package org.apache.juneau.httppart.uon;
 
 import java.io.*;
 
 import org.apache.juneau.*;
+import org.apache.juneau.httppart.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.uon.*;
 
@@ -75,8 +76,19 @@ public class UonPartSerializer extends UonSerializer implements HttpPartSerializ
 	// Entry point methods
 	//--------------------------------------------------------------------------------
 
-	@Override /* PartSerializer */
+	/**
+	 * 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.
+	 */
 	public String serialize(HttpPartType type, Object value) {
+		return serialize(type, null, value);
+	}
+
+	@Override /* PartSerializer */
+	public String serialize(HttpPartType type, HttpPartSchema schema, Object value) {
 		try {
 			// Shortcut for simple types.
 			ClassMeta<?> cm = getClassMetaForObject(value);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartSerializerBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/uon/UonPartSerializerBuilder.java
similarity index 99%
rename from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartSerializerBuilder.java
rename to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/uon/UonPartSerializerBuilder.java
index c26cbf8..6e14ad1 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartSerializerBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/uon/UonPartSerializerBuilder.java
@@ -10,7 +10,7 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.httppart;
+package org.apache.juneau.httppart.uon;
 
 import java.util.*;
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DateUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DateUtils.java
index 57cfce3..a92ff8a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DateUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DateUtils.java
@@ -12,6 +12,8 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.internal;
 
+import static org.apache.juneau.internal.StringUtils.*;
+
 import java.lang.ref.*;
 import java.text.*;
 import java.util.*;
@@ -114,7 +116,7 @@ public final class DateUtils {
 	 * @return The parsed value, or <jk>null</jk> if the string was <jk>null</jk> or empty.
 	 */
 	public static Calendar parseISO8601Calendar(String s) {
-		if (StringUtils.isEmpty(s))
+		if (isEmpty(s))
 			return null;
 		return DatatypeConverter.parseDateTime(toValidISO8601DT(s));
 	}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/IOUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/IOUtils.java
index 606d7f8..ad0780c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/IOUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/IOUtils.java
@@ -13,6 +13,7 @@
 package org.apache.juneau.internal;
 
 import static org.apache.juneau.internal.ThrowableUtils.*;
+import static org.apache.juneau.internal.StringUtils.*;
 
 import java.io.*;
 import java.nio.charset.*;
@@ -364,7 +365,7 @@ public final class IOUtils {
 	 */
 	public static int getBufferSize(String contentLength) {
 		try {
-			if (! StringUtils.isEmpty(contentLength)) {
+			if (isNotEmpty(contentLength)) {
 				long l = Long.decode(contentLength);
 				if (l > 1048576)
 					return 1048576;
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/JuneauLogger.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/JuneauLogger.java
index 77100f9..9edf71f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/JuneauLogger.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/JuneauLogger.java
@@ -272,7 +272,7 @@ public class JuneauLogger extends java.util.logging.Logger {
 	}
 
 	private static String resolveResourceBundleName(Class<?> forClass, String path) {
-		if (StringUtils.isEmpty(path))
+		if (isEmpty(path))
 			return null;
 		String rb = rbMap.get(forClass);
 		if (rb == null) {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
index f1d7c09..d679771 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
@@ -802,6 +802,28 @@ public final class StringUtils {
 	}
 
 	/**
+	 * Returns <jk>true</jk> if specified string is not <jk>null</jk> or empty.
+	 * 
+	 * @param s The string to check.
+	 * @return <jk>true</jk> if specified string is not <jk>null</jk> or empty.
+	 */
+	public static boolean isNotEmpty(String s) {
+		return ! isEmpty(s);
+	}
+
+	/**
+	 * Returns <jk>true</jk> if specified string is not <jk>null</jk> or it's {@link #toString()} method doesn't return an empty
+	 * string.
+	 * 
+	 * @param s The string to check.
+	 * @return
+	 * 	<jk>true</jk> if specified string is not <jk>null</jk> or it's {@link #toString()} method doesn't return an empty string.
+	 */
+	public static boolean isNotEmpty(Object s) {
+		return ! isEmpty(s);
+	}
+
+	/**
 	 * Returns <jk>null</jk> if the specified string is <jk>null</jk> or empty.
 	 * 
 	 * @param s The string to check.
@@ -2010,7 +2032,7 @@ public final class StringUtils {
 	 */
 	public static String firstNonEmpty(String...s) {
 		for (String ss : s)
-			if (! isEmpty(ss))
+			if (isNotEmpty(ss))
 				return ss;
 		return null;
 	}
@@ -2163,6 +2185,47 @@ public final class StringUtils {
 	}
 
 	/**
+	 * Parses a string that can consist of either a JSON array or comma-delimited list.
+	 * 
+	 * <p>
+	 * The type of string is auto-detected.
+	 * 
+	 * @param s The string to parse.
+	 * @return The parsed string.
+	 * @throws ParseException
+	 */
+	public static ObjectList parseListOrCdl(String s) throws ParseException {
+		if (isEmpty(s))
+			return null;
+		if (! isObjectList(s, true))
+			return new ObjectList(Arrays.asList(StringUtils.split(s.trim(), ',')));
+		return new ObjectList(s);
+	}
+	
+	/**
+	 * Returns <jk>true</jk> if the specified string is valid JSON.
+	 * 
+	 * <p>
+	 * Leading and trailing spaces are ignored.
+	 * <br>Leading and trailing comments are not allowed.
+	 * 
+	 * @param s The string to test.
+	 * @return <jk>true</jk> if the specified string is valid JSON.
+	 */
+	public static boolean isJson(String s) {
+		if (s == null)
+			return false;
+		char c1 = StringUtils.firstNonWhitespaceChar(s), c2 = StringUtils.lastNonWhitespaceChar(s);
+		if (c1 == '{' && c2 == '}' || c1 == '[' && c2 == ']' || c1 == '\'' && c2 == '\'')
+			return true;
+		if (StringUtils.isOneOf(s, "true","false","null"))
+			return true;
+		if (StringUtils.isNumeric(s))
+			return true;
+		return false;
+	}
+	
+	/**
 	 * Returns <jk>true</jk> if the specified string appears to be a JSON object.
 	 * 
 	 * @param o The object to test.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/VersionRange.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/VersionRange.java
index bf8c7e5..43ff5ff 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/VersionRange.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/VersionRange.java
@@ -12,6 +12,8 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.internal;
 
+import static org.apache.juneau.internal.StringUtils.*;
+
 /**
  * Represents an OSGi-style version range like <js>"1.2"</js> or <js>"[1.0,2.0)"</js>.
  * 
@@ -62,7 +64,7 @@ public class VersionRange {
 	 * @return <jk>true</jk> if the specified version string matches this version range.
 	 */
 	public boolean matches(String v) {
-		if (StringUtils.isEmpty(v))
+		if (isEmpty(v))
 			return (minVersion == null && maxVersion == null);
 		Version ver = new Version(v);
 		if (minVersion != null && ! ver.isAtLeast(minVersion, minExclusive))
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 290090a..4332c79 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
@@ -260,7 +260,7 @@ public class JsonSerializer extends WriterSerializer {
 	/** Default serializer, all default settings.*/
 	public static final JsonSerializer DEFAULT_READABLE = new Readable(PropertyStore.DEFAULT);
 
-	/** Default serializer, single quotes, simple mode. */
+	/** Default serializer, single quotes, {@link #JSON_simpleMode simple mode}. */
 	public static final JsonSerializer DEFAULT_LAX = new Simple(PropertyStore.DEFAULT);
 
 	/** Default serializer, single quotes, simple mode, with whitespace. */
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/AList.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/AList.java
index b391bf5..8f6faaf 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/AList.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/AList.java
@@ -60,4 +60,17 @@ public final class AList<T> extends LinkedList<T> {
 		addAll(Arrays.asList(t));
 		return this;
 	}
+
+	/**
+	 * Adds an entry to this list if the boolean flag is <jk>true</jk>.
+	 * 
+	 * @param b The boolean flag.
+	 * @param val The value to add.
+	 * @return This object (for method chaining).
+	 */
+	public AList<T> appendIf(boolean b, T val) {
+		if (b)
+			append(val);
+		return this;
+	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/CalendarUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/CalendarUtils.java
index a6de8a9..c174920 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/CalendarUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/CalendarUtils.java
@@ -13,6 +13,7 @@
 package org.apache.juneau.utils;
 
 import static org.apache.juneau.internal.DateUtils.*;
+import static org.apache.juneau.internal.StringUtils.*;
 
 import java.text.*;
 import java.util.*;
@@ -20,8 +21,6 @@ import java.util.concurrent.*;
 
 import javax.xml.bind.*;
 
-import org.apache.juneau.internal.*;
-
 /**
  * Utility class for converting {@link Calendar} and {@link Date} objects to common serialized forms.
  */
@@ -560,7 +559,7 @@ public class CalendarUtils {
 	 * @throws Exception
 	 */
 	public static final Calendar parseCalendar(String in, CalendarUtils.Format format, Locale locale, TimeZone timeZone) throws Exception {
-		if (StringUtils.isEmpty(in))
+		if (isEmpty(in))
 			return null;
 		if (timeZone == null)
 			timeZone = TimeZone.getDefault();
@@ -632,7 +631,7 @@ public class CalendarUtils {
 	 * @throws Exception
 	 */
 	public static final Date parseDate(String in, CalendarUtils.Format format, Locale locale, TimeZone timeZone) throws Exception {
-		if (StringUtils.isEmpty(in))
+		if (isEmpty(in))
 			return null;
 		if (timeZone == null)
 			timeZone = TimeZone.getDefault();
diff --git a/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/vars/ArgsVar.java b/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/vars/ArgsVar.java
index b0b45f5..c1159cd 100644
--- a/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/vars/ArgsVar.java
+++ b/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/vars/ArgsVar.java
@@ -79,7 +79,7 @@ public class ArgsVar extends DefaultingVar {
 			this.args = ARGS;
 		else {
 			String s = System.getProperty("sun.java.command");
-			if (! isEmpty(s)) {
+			if (isNotEmpty(s)) {
 				int i = s.indexOf(' ');
 				args = new Args(i == -1 ? "" : s.substring(i+1));
 			} else {
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreResource.java
index d903e2b..4298914 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreResource.java
@@ -279,7 +279,7 @@ public class PetStoreResource extends BasicRestServletJena {
 			@Query(
 				name="status", 
 				description="Status values that need to be considered for filter.", 
-				required="true", 
+				required=true, 
 				type="array",
 				items=@Items(
 					type="string",
@@ -311,7 +311,7 @@ public class PetStoreResource extends BasicRestServletJena {
 			@Query(
 				name="tags", 
 				description="Tags to filter by", 
-				required="true", 
+				required=true, 
 				example="['tag1','tag2']"
 			) 
 			String[] tags
@@ -332,7 +332,7 @@ public class PetStoreResource extends BasicRestServletJena {
 		)
 	)
 	public Ok deletePet(
-			@Header(name="api_key", description="Security API key", required="true", example="foobar") String apiKey, 
+			@Header(name="api_key", description="Security API key", required=true, example="foobar") String apiKey, 
 			@Path(name="petId", description="Pet id to delete", example="123") long petId
 		) throws IdNotFound, NotAcceptable {
 		
@@ -354,7 +354,7 @@ public class PetStoreResource extends BasicRestServletJena {
 	public Ok uploadImage(
 			@Path(name="petId", description="ID of pet to update", example="123") long petId, 
 			@FormData(name="additionalMetadata", description="Additional data to pass to server", example="Foobar") String additionalMetadata, 
-			@FormData(name="file", description="file to upload", required="true", type="file") byte[] file
+			@FormData(name="file", description="file to upload", required=true, type="file") byte[] file
 		) throws NotAcceptable, UnsupportedMediaType {
 		
 		return OK;
@@ -591,8 +591,8 @@ public class PetStoreResource extends BasicRestServletJena {
 		)
 	)
 	public Ok login(
-			@Query(name="username", description="The username for login", required="true", example="myuser") String username, 
-			@Query(name="password", description="The password for login in clear text", required="true", example="abc123") String password, 
+			@Query(name="username", description="The username for login", required=true, example="myuser") String username, 
+			@Query(name="password", description="The password for login in clear text", required=true, example="abc123") String password, 
 			@ResponseHeader(name="X-Rate-Limit", type="integer", format="int32", description="Calls per hour allowed by the user.", example="123") Value<Integer> rateLimit,
 			ExpiresAfter expiresAfter,
 			RestRequest req, 
diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Microservice.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Microservice.java
index 9d609bd..9a827dd 100755
--- a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Microservice.java
+++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Microservice.java
@@ -761,7 +761,7 @@ public abstract class Microservice implements ConfigEventListener {
 		Config cf = getConfig();
 		logger = Logger.getLogger("");
 		String logFile = cf.getString("Logging/logFile");
-		if (! isEmpty(logFile)) {
+		if (isNotEmpty(logFile)) {
 			LogManager.getLogManager().reset();
 			String logDir = cf.getString("Logging/logDir", ".");
 			mkdirs(new File(logDir), false);
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 cd602f0..34079b6 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
@@ -22,6 +22,7 @@ import java.util.*;
 
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.uon.*;
 import org.apache.juneau.remoteable.*;
 import org.apache.juneau.remoteable.FormData;
 import org.apache.juneau.remoteable.Header;
@@ -1998,7 +1999,7 @@ public class RequestBeanProxyTest {
 
 	public static class XSerializer implements HttpPartSerializer {
 		@Override
-		public String serialize(HttpPartType type, Object value) {
+		public String serialize(HttpPartType type, HttpPartSchema schema, Object value) {
 			if (value == null)
 				return "NULL";
 			if (value instanceof Collection)
@@ -2011,7 +2012,7 @@ public class RequestBeanProxyTest {
 
 	public static class ListSerializer implements HttpPartSerializer {
 		@Override
-		public String serialize(HttpPartType type, Object value) {
+		public String serialize(HttpPartType type, HttpPartSchema schema, Object value) {
 			if (value == null)
 				return "NULL";
 			if (value instanceof Collection)
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 d843659..8454f34 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
@@ -22,6 +22,7 @@ import java.util.concurrent.atomic.*;
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.html.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.uon.*;
 import org.apache.juneau.jena.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.msgpack.*;
@@ -3847,7 +3848,7 @@ public class ThirdPartyProxyTest extends RestTestcase {
 
 	public static class DummyPartSerializer implements HttpPartSerializer {
 		@Override
-		public String serialize(HttpPartType type, Object value) {
+		public String serialize(HttpPartType type, HttpPartSchema schema, Object value) {
 			return "dummy-"+value;
 		}
 	}
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/NameValuePairs.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/NameValuePairs.java
index 0fc7067..52b89ec 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/NameValuePairs.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/NameValuePairs.java
@@ -20,6 +20,7 @@ import org.apache.http.*;
 import org.apache.http.client.entity.*;
 import org.apache.http.message.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.oapi.*;
 import org.apache.juneau.urlencoding.*;
 
 /**
@@ -76,11 +77,17 @@ public final class NameValuePairs extends LinkedList<NameValuePair> {
 	 * 
 	 * @param name The pair name.
 	 * @param value The pair value.
-	 * @param partSerializer The serializer to use for converting values to simple strings.
+	 * @param serializer
+	 * 	The serializer to use for serializing the value to a string value.
+	 * @param schema 
+	 * 	The schema object that defines the format of the output.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the parser.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the serializer parser is not a subclass of {@link OapiPartSerializer}.
 	 * @return This object (for method chaining).
 	 */
-	public NameValuePairs append(String name, Object value, HttpPartSerializer partSerializer) {
-		super.add(new SerializedNameValuePair(name, value, partSerializer));
+	public NameValuePairs append(String name, Object value, HttpPartSerializer serializer, HttpPartSchema schema) {
+		super.add(new SerializedNameValuePair(name, value, serializer, schema));
 		return this;
 	}
 }
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 4a31b43..9d01ea7 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
@@ -37,6 +37,8 @@ import org.apache.juneau.*;
 import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.oapi.*;
+import org.apache.juneau.httppart.uon.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.parser.ParseException;
@@ -193,26 +195,31 @@ public final class RestCall extends BeanSession implements Closeable {
 	 * 	Can also be {@link Map}, {@link String}, {@link NameValuePairs}, or bean if the name is null/blank/*.
 	 * 	If a {@link String} and the name is null/blank/*, then calls {@link URIBuilder#setCustomQuery(String)}.
 	 * @param skipIfEmpty Don't add the pair if the value is empty.
-	 * @param partSerializer
-	 * 	The part serializer to use to convert the value to a string.
+	 * @param serializer
+	 * 	The serializer to use for serializing the value to a string value.
 	 * 	If <jk>null</jk>, then the URL-encoding serializer defined on the client is used.
+	 * @param schema 
+	 * 	The schema object that defines the format of the output.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the serializer.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part serializer is not a subclass of {@link OapiPartSerializer}.
 	 * @return This object (for method chaining).
 	 * @throws RestCallException
 	 */
-	public RestCall query(String name, Object value, boolean skipIfEmpty, HttpPartSerializer partSerializer) throws RestCallException {
-		if (partSerializer == null)
-			partSerializer = client.getPartSerializer();
+	public RestCall query(String name, Object value, boolean skipIfEmpty, HttpPartSerializer serializer, HttpPartSchema schema) throws RestCallException {
+		if (serializer == null)
+			serializer = client.getPartSerializer();
 		if (! ("*".equals(name) || isEmpty(name))) {
 			if (value != null && ! (ObjectUtils.isEmpty(value) && skipIfEmpty))
-				uriBuilder.addParameter(name, partSerializer.serialize(HttpPartType.QUERY, value));
+				uriBuilder.addParameter(name, serializer.serialize(HttpPartType.QUERY, schema, value));
 		} else if (value instanceof NameValuePairs) {
 			for (NameValuePair p : (NameValuePairs)value)
-				query(p.getName(), p.getValue(), skipIfEmpty, SimpleUonPartSerializer.DEFAULT);
+				query(p.getName(), p.getValue(), skipIfEmpty, SimpleUonPartSerializer.DEFAULT, schema);
 		} else if (value instanceof Map) {
 			for (Map.Entry<String,Object> p : ((Map<String,Object>) value).entrySet())
-				query(p.getKey(), p.getValue(), skipIfEmpty, partSerializer);
+				query(p.getKey(), p.getValue(), skipIfEmpty, serializer, schema);
 		} else if (isBean(value)) {
-			return query(name, toBeanMap(value), skipIfEmpty, partSerializer);
+			return query(name, toBeanMap(value), skipIfEmpty, serializer, schema);
 		} else if (value instanceof Reader) {
 			try {
 				uriBuilder.setCustomQuery(read(value));
@@ -221,7 +228,7 @@ public final class RestCall extends BeanSession implements Closeable {
 			}
 		} else if (value instanceof CharSequence) {
 			String s = value.toString();
-			if (! isEmpty(s))
+			if (isNotEmpty(s))
 				uriBuilder.setCustomQuery(s);
 		} else {
 			throw new FormattedRuntimeException("Invalid name ''{0}'' passed to query(name,value,skipIfEmpty) for data type ''{1}''", name, getReadableClassNameForObject(value));
@@ -238,7 +245,7 @@ public final class RestCall extends BeanSession implements Closeable {
 	 * @throws RestCallException
 	 */
 	public RestCall query(String name, Object value) throws RestCallException {
-		return query(name, value, false, null);
+		return query(name, value, false, null, null);
 	}
 
 	/**
@@ -264,7 +271,7 @@ public final class RestCall extends BeanSession implements Closeable {
 	 * @throws RestCallException
 	 */
 	public RestCall queryIfNE(String name, Object value) throws RestCallException {
-		return query(name, value, true, null);
+		return query(name, value, true, null, null);
 	}
 
 	/**
@@ -278,7 +285,7 @@ public final class RestCall extends BeanSession implements Closeable {
 	 * @throws RestCallException
 	 */
 	public RestCall queryIfNE(Map<String,Object> params) throws RestCallException {
-		return query(null, params, true, null);
+		return query(null, params, true, null, null);
 	}
 
 	/**
@@ -302,29 +309,34 @@ public final class RestCall extends BeanSession implements Closeable {
 	 * 	The parameter value converted to a string using UON notation.
 	 * 	Can also be {@link Map}, {@link NameValuePairs}, or bean if the name is null/blank/*.
 	 * @param skipIfEmpty Don't add the pair if the value is empty.
-	 * @param partSerializer
-	 * 	The part serializer to use to convert the value to a string.
+	 * @param serializer
+	 * 	The serializer to use for serializing the value to a string value.
 	 * 	If <jk>null</jk>, then the URL-encoding serializer defined on the client is used.
+	 * @param schema 
+	 * 	The schema object that defines the format of the output.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the serializer.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part serializer is not a subclass of {@link OapiPartSerializer}.
 	 * @return This object (for method chaining).
 	 * @throws RestCallException
 	 */
-	public RestCall formData(String name, Object value, boolean skipIfEmpty, HttpPartSerializer partSerializer) throws RestCallException {
+	public RestCall formData(String name, Object value, boolean skipIfEmpty, HttpPartSerializer serializer, HttpPartSchema schema) throws RestCallException {
 		if (formData == null)
 			formData = new NameValuePairs();
-		if (partSerializer == null)
-			partSerializer = client.getPartSerializer();
+		if (serializer == null)
+			serializer = client.getPartSerializer();
 		if (! ("*".equals(name) || isEmpty(name))) {
 			if (value != null && ! (ObjectUtils.isEmpty(value) && skipIfEmpty))
-				formData.add(new SerializedNameValuePair(name, value, partSerializer));
+				formData.add(new SerializedNameValuePair(name, value, serializer, schema));
 		} else if (value instanceof NameValuePairs) {
 			for (NameValuePair p : (NameValuePairs)value)
 				if (p.getValue() != null && ! (isEmpty(p.getValue()) && skipIfEmpty))
 					formData.add(p);
 		} else if (value instanceof Map) {
 			for (Map.Entry<String,Object> p : ((Map<String,Object>) value).entrySet())
-				formData(p.getKey(), p.getValue(), skipIfEmpty, partSerializer);
+				formData(p.getKey(), p.getValue(), skipIfEmpty, serializer, schema);
 		} else if (isBean(value)) {
-			return formData(name, toBeanMap(value), skipIfEmpty, partSerializer);
+			return formData(name, toBeanMap(value), skipIfEmpty, serializer, schema);
 		} else if (value instanceof Reader) {
 			contentType("application/x-www-form-urlencoded");
 			input(value);
@@ -352,7 +364,7 @@ public final class RestCall extends BeanSession implements Closeable {
 	 * @throws RestCallException If name was null/blank and value wasn't a {@link Map} or {@link NameValuePairs}.
 	 */
 	public RestCall formData(String name, Object value) throws RestCallException {
-		return formData(name, value, false, null);
+		return formData(name, value, false, null, null);
 	}
 
 	/**
@@ -389,7 +401,7 @@ public final class RestCall extends BeanSession implements Closeable {
 	 * @throws RestCallException
 	 */
 	public RestCall formDataIfNE(String name, Object value) throws RestCallException {
-		return formData(name, value, true, null);
+		return formData(name, value, true, null, null);
 	}
 
 	/**
@@ -403,7 +415,7 @@ public final class RestCall extends BeanSession implements Closeable {
 	 * @throws RestCallException
 	 */
 	public RestCall formDataIfNE(Map<String,Object> params) throws RestCallException {
-		return formData(null, params, true, null);
+		return formData(null, params, true, null, null);
 	}
 
 	/**
@@ -411,30 +423,35 @@ public final class RestCall extends BeanSession implements Closeable {
 	 * 
 	 * @param name The path variable name.
 	 * @param value The replacement value.
-	 * @param partSerializer
-	 * 	The part serializer to use to convert the value to a string.
+	 * @param serializer
+	 * 	The serializer to use for serializing the value to a string value.
 	 * 	If <jk>null</jk>, then the URL-encoding serializer defined on the client is used.
+	 * @param schema 
+	 * 	The schema object that defines the format of the output.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the serializer.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part serializer is not a subclass of {@link OapiPartSerializer}.
 	 * @return This object (for method chaining).
 	 * @throws RestCallException If variable could not be found in path.
 	 */
-	public RestCall path(String name, Object value, HttpPartSerializer partSerializer) throws RestCallException {
+	public RestCall path(String name, Object value, HttpPartSerializer serializer, HttpPartSchema schema) throws RestCallException {
 		String path = uriBuilder.getPath();
-		if (partSerializer == null)
-			partSerializer = client.getPartSerializer();
+		if (serializer == null)
+			serializer = client.getPartSerializer();
 		if (! ("*".equals(name) || isEmpty(name))) {
 			String var = "{" + name + "}";
 			if (path.indexOf(var) == -1)
 				throw new RestCallException("Path variable {"+name+"} was not found in path.");
-			String newPath = path.replace(var, partSerializer.serialize(HttpPartType.PATH, value));
+			String newPath = path.replace(var, serializer.serialize(HttpPartType.PATH, schema, value));
 			uriBuilder.setPath(newPath);
 		} else if (value instanceof NameValuePairs) {
 			for (NameValuePair p : (NameValuePairs)value)
-				path(p.getName(), p.getValue(), partSerializer);
+				path(p.getName(), p.getValue(), serializer, schema);
 		} else if (value instanceof Map) {
 			for (Map.Entry<String,Object> p : ((Map<String,Object>) value).entrySet())
-				path(p.getKey(), p.getValue(), partSerializer);
+				path(p.getKey(), p.getValue(), serializer, schema);
 		} else if (isBean(value)) {
-			return path(name, toBeanMap(value), partSerializer);
+			return path(name, toBeanMap(value), serializer, schema);
 		} else if (value != null) {
 			throw new FormattedRuntimeException("Invalid name ''{0}'' passed to path(name,value) for data type ''{1}''", name, getReadableClassNameForObject(value));
 		}
@@ -450,7 +467,7 @@ public final class RestCall extends BeanSession implements Closeable {
 	 * @throws RestCallException If variable could not be found in path.
 	 */
 	public RestCall path(String name, Object value) throws RestCallException {
-		return path(name, value, null);
+		return path(name, value, null, null);
 	}
 
 	/**
@@ -548,26 +565,31 @@ public final class RestCall extends BeanSession implements Closeable {
 	 * 	The name can be null/empty if the value is a {@link Map}.
 	 * @param value The header value.
 	 * @param skipIfEmpty Don't add the header if the name is null/empty.
-	 * @param partSerializer
-	 * 	The part serializer to use to convert the value to a string.
+	 * @param serializer
+	 * 	The serializer to use for serializing the value to a string value.
 	 * 	If <jk>null</jk>, then the URL-encoding serializer defined on the client is used.
+	 * @param schema 
+	 * 	The schema object that defines the format of the output.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the serializer.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part serializer is not a subclass of {@link OapiPartSerializer}.
 	 * @return This object (for method chaining).
 	 * @throws RestCallException
 	 */
-	public RestCall header(String name, Object value, boolean skipIfEmpty, HttpPartSerializer partSerializer) throws RestCallException {
-		if (partSerializer == null)
-			partSerializer = client.getPartSerializer();
+	public RestCall header(String name, Object value, boolean skipIfEmpty, HttpPartSerializer serializer, HttpPartSchema schema) throws RestCallException {
+		if (serializer == null)
+			serializer = client.getPartSerializer();
 		if (! ("*".equals(name) || isEmpty(name))) {
 			if (value != null && ! (ObjectUtils.isEmpty(value) && skipIfEmpty))
-				request.setHeader(name, partSerializer.serialize(HttpPartType.HEADER, value));
+				request.setHeader(name, serializer.serialize(HttpPartType.HEADER, schema, value));
 		} else if (value instanceof NameValuePairs) {
 			for (NameValuePair p : (NameValuePairs)value)
-				header(p.getName(), p.getValue(), skipIfEmpty, SimpleUonPartSerializer.DEFAULT);
+				header(p.getName(), p.getValue(), skipIfEmpty, SimpleUonPartSerializer.DEFAULT, schema);
 		} else if (value instanceof Map) {
 			for (Map.Entry<String,Object> p : ((Map<String,Object>) value).entrySet())
-				header(p.getKey(), p.getValue(), skipIfEmpty, partSerializer);
+				header(p.getKey(), p.getValue(), skipIfEmpty, serializer, schema);
 		} else if (isBean(value)) {
-			return header(name, toBeanMap(value), skipIfEmpty, partSerializer);
+			return header(name, toBeanMap(value), skipIfEmpty, serializer, schema);
 		} else {
 			throw new FormattedRuntimeException("Invalid name ''{0}'' passed to header(name,value,skipIfEmpty) for data type ''{1}''", name, getReadableClassNameForObject(value));
 		}
@@ -586,7 +608,7 @@ public final class RestCall extends BeanSession implements Closeable {
 	 * @throws RestCallException
 	 */
 	public RestCall header(String name, Object value) throws RestCallException {
-		return header(name, value, false, null);
+		return header(name, value, false, null, null);
 	}
 
 	/**
@@ -597,7 +619,7 @@ public final class RestCall extends BeanSession implements Closeable {
 	 * @throws RestCallException
 	 */
 	public RestCall headers(Map<String,Object> values) throws RestCallException {
-		return header(null, values, false, null);
+		return header(null, values, false, null, null);
 	}
 
 	/**
@@ -614,7 +636,7 @@ public final class RestCall extends BeanSession implements Closeable {
 	 * @throws RestCallException
 	 */
 	public RestCall headerIfNE(String name, Object value) throws RestCallException {
-		return header(name, value, true, null);
+		return header(name, value, true, null, null);
 	}
 
 	/**
@@ -628,7 +650,7 @@ public final class RestCall extends BeanSession implements Closeable {
 	 * @throws RestCallException
 	 */
 	public RestCall headersIfNE(Map<String,Object> values) throws RestCallException {
-		return header(null, values, true, null);
+		return header(null, values, true, null, null);
 	}
 
 	/**
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
index 7ea8f29..4ec7076 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
@@ -30,6 +30,7 @@ import org.apache.http.entity.*;
 import org.apache.http.impl.client.*;
 import org.apache.juneau.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.uon.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
@@ -1014,16 +1015,16 @@ public class RestClient extends BeanContext implements Closeable {
 							rc.serializer(serializer).parser(parser);
 
 							for (RemoteMethodArg a : rmm.getPathArgs())
-								rc.path(a.name, args[a.index], a.serializer);
+								rc.path(a.name, args[a.index], a.serializer, null);
 
 							for (RemoteMethodArg a : rmm.getQueryArgs())
-								rc.query(a.name, args[a.index], a.skipIfNE, a.serializer);
+								rc.query(a.name, args[a.index], a.skipIfNE, a.serializer, null);
 
 							for (RemoteMethodArg a : rmm.getFormDataArgs())
-								rc.formData(a.name, args[a.index], a.skipIfNE, a.serializer);
+								rc.formData(a.name, args[a.index], a.skipIfNE, a.serializer, null);
 
 							for (RemoteMethodArg a : rmm.getHeaderArgs())
-								rc.header(a.name, args[a.index], a.skipIfNE, a.serializer);
+								rc.header(a.name, args[a.index], a.skipIfNE, a.serializer, null);
 
 							if (rmm.getBodyArg() != null)
 								rc.input(args[rmm.getBodyArg()]);
@@ -1039,32 +1040,32 @@ public class RestClient extends BeanContext implements Closeable {
 
 										Path p = pMeta.getAnnotation(Path.class);
 										if (p != null)
-											rc.path(getName(p.name(), p.value(), pMeta), val, getPartSerializer(p.serializer(), rma.serializer));
+											rc.path(getName(p.name(), p.value(), pMeta), val, getPartSerializer(p.serializer(), rma.serializer), null);
 
 										if (val != null) {
 											Query q1 = pMeta.getAnnotation(Query.class);
 											if (q1 != null)
-												rc.query(getName(q1.name(), q1.value(), pMeta), val, q1.skipIfEmpty(), getPartSerializer(q1.serializer(), rma.serializer));
+												rc.query(getName(q1.name(), q1.value(), pMeta), val, q1.skipIfEmpty(), getPartSerializer(q1.serializer(), rma.serializer), null);
 
 											QueryIfNE q2 = pMeta.getAnnotation(QueryIfNE.class);
 											if (q2 != null)
-												rc.query(getName(q2.name(), q2.value(), pMeta), val, true, getPartSerializer(q2.serializer(), rma.serializer));
+												rc.query(getName(q2.name(), q2.value(), pMeta), val, true, getPartSerializer(q2.serializer(), rma.serializer), null);
 
 											FormData f1 = pMeta.getAnnotation(FormData.class);
 											if (f1 != null)
-												rc.formData(getName(f1.name(), f1.value(), pMeta), val, f1.skipIfEmpty(), getPartSerializer(f1.serializer(), rma.serializer));
+												rc.formData(getName(f1.name(), f1.value(), pMeta), val, f1.skipIfEmpty(), getPartSerializer(f1.serializer(), rma.serializer), null);
 
 											FormDataIfNE f2 = pMeta.getAnnotation(FormDataIfNE.class);
 											if (f2 != null)
-												rc.formData(getName(f2.name(), f2.value(), pMeta), val, true, getPartSerializer(f2.serializer(), rma.serializer));
+												rc.formData(getName(f2.name(), f2.value(), pMeta), val, true, getPartSerializer(f2.serializer(), rma.serializer), null);
 
 											org.apache.juneau.remoteable.Header h1 = pMeta.getAnnotation(org.apache.juneau.remoteable.Header.class);
 											if (h1 != null)
-												rc.header(getName(h1.name(), h1.value(), pMeta), val, h1.skipIfEmpty(), getPartSerializer(h1.serializer(), rma.serializer));
+												rc.header(getName(h1.name(), h1.value(), pMeta), val, h1.skipIfEmpty(), getPartSerializer(h1.serializer(), rma.serializer), null);
 
 											HeaderIfNE h2 = pMeta.getAnnotation(HeaderIfNE.class);
 											if (h2 != null)
-												rc.header(getName(h2.name(), h2.value(), pMeta), val, true, getPartSerializer(h2.serializer(), rma.serializer));
+												rc.header(getName(h2.name(), h2.value(), pMeta), val, true, getPartSerializer(h2.serializer(), rma.serializer), null);
 										}
 									}
 								}
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 a0bdff8..84b9fc4 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
@@ -48,6 +48,7 @@ import org.apache.juneau.*;
 import org.apache.juneau.html.*;
 import org.apache.juneau.http.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.uon.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.msgpack.*;
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 decd32b..f380302 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
@@ -14,6 +14,7 @@ package org.apache.juneau.rest.client;
 
 import org.apache.http.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.oapi.*;
 import org.apache.juneau.urlencoding.*;
 
 /**
@@ -32,18 +33,26 @@ public final class SerializedNameValuePair implements NameValuePair {
 	private String name;
 	private Object value;
 	private HttpPartSerializer serializer;
+	private HttpPartSchema schema;
 
 	/**
 	 * Constructor.
 	 * 
 	 * @param name The parameter name.
 	 * @param value The POJO to serialize to the parameter value.
-	 * @param serializer The serializer to use to convert the value to a string.
+	 * @param serializer
+	 * 	The serializer to use for serializing the value to a string value.
+	 * @param schema 
+	 * 	The schema object that defines the format of the output.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the serializer.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part serializer is not a subclass of {@link OapiPartSerializer}.
 	 */
-	public SerializedNameValuePair(String name, Object value, HttpPartSerializer serializer) {
+	public SerializedNameValuePair(String name, Object value, HttpPartSerializer serializer, HttpPartSchema schema) {
 		this.name = name;
 		this.value = value;
 		this.serializer = serializer;
+		this.schema = schema;
 	}
 
 	@Override /* NameValuePair */
@@ -53,6 +62,6 @@ public final class SerializedNameValuePair implements NameValuePair {
 
 	@Override /* NameValuePair */
 	public String getValue() {
-		return serializer.serialize(HttpPartType.FORMDATA, value);
+		return serializer.serialize(HttpPartType.FORMDATA, schema, value);
 	}
 }
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 c377a4a..39009ae 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
@@ -761,9 +761,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 			if (s.isEmpty())
 				return null;
 			s = vs.resolve(s.trim());
-			if (! isObjectList(s, true))
-				return new ObjectList(Arrays.asList(StringUtils.split(s, ',')));
-			return new ObjectList(s);
+			return StringUtils.parseListOrCdl(s);
 		} catch (ParseException e) {
 			throw new SwaggerException(e, "Malformed swagger JSON array encountered in "+location+".", locationArgs);
 		}
@@ -900,7 +898,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 		boolean isOk = "ok".equals(in), isBody = "body".equals(in);
 		
 		String sex = example.toString();
-		if (RestUtils.isJson(sex)) {
+		if (isJson(sex)) {
 			example = JsonParser.DEFAULT.parse(JsonSerializer.DEFAULT.serialize(example), type);
 		} else {
 			ClassMeta<?> cm = js.getClassMeta(type);
@@ -935,7 +933,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 			}
 		} else {
 			String paramName = piri.getString("name");
-			String s = sm.partSerializer.serialize(HttpPartType.valueOf(in.toUpperCase()), example);
+			String s = sm.partSerializer.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 5ab2582..1ec7790 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
@@ -24,6 +24,7 @@ import javax.servlet.*;
 import org.apache.juneau.*;
 import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.*;
+import org.apache.juneau.httppart.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.exception.*;
@@ -51,6 +52,8 @@ public class RequestBody {
 	private int contentLength = 0;
 	private MediaType mediaType;
 	private Parser parser;
+	private HttpPartParser partParser;
+	private HttpPartSchema schema;
 
 	RequestBody(RestRequest req) {
 		this.req = req;
@@ -88,6 +91,16 @@ public class RequestBody {
 		return this;
 	}
 
+	RequestBody partParser(HttpPartParser partParser) {
+		this.partParser = partParser;
+		return this;
+	}
+
+	RequestBody schema(HttpPartSchema schema) {
+		this.schema = schema;
+		return this;
+	}
+
 	boolean isLoaded() {
 		return body != null;
 	}
@@ -178,7 +191,7 @@ public class RequestBody {
 	 * 	for the specified type.
 	 */
 	public <T> T asType(Class<T> type) throws IOException, ParseException {
-		return parse(beanSession.getClassMeta(type));
+		return parse(getClassMeta(type));
 	}
 
 	/**
@@ -223,7 +236,7 @@ public class RequestBody {
 	 * @return The input parsed to a POJO.
 	 */
 	public <T> T asType(Type type, Type...args) {
-		return (T)parse(beanSession.getClassMeta(type, args));
+		return parse(this.<T>getClassMeta(type, args));
 	}
 
 	/**
@@ -417,7 +430,10 @@ public class RequestBody {
 					req.getProperties().append("mediaType", mediaType).append("characterEncoding", req.getCharacterEncoding());
 					ParserSession session = p.createSession(new ParserSessionArgs(req.getProperties(), req.getJavaMethod(), locale, timeZone, mediaType, req.getContext().getResource()));
 					try (Closeable in = session.isReaderParser() ? getUnbufferedReader() : getInputStream()) {
-						return session.parse(in, cm);
+						T o = session.parse(in, cm);
+						if (schema != null)
+							schema.validateOutput(o, cm.getBeanContext());
+						return o;
 					}
 				} catch (ParseException e) {
 					throw new BadRequest(e,
@@ -434,8 +450,21 @@ public class RequestBody {
 				return cm.getInputStreamTransform().transform(getInputStream());
 			
 			MediaType mt = getMediaType();
-			if ((isEmpty(mt) || mt.toString().startsWith("text/plain")) && cm.hasStringTransform())
-				return cm.getStringTransform().transform(asString());
+			if ((isEmpty(mt) || mt.toString().startsWith("text/plain"))) {
+				if (partParser != null) {
+					try {
+						String in = asString();
+						return partParser.parse(HttpPartType.BODY, schema, isEmpty(in) ? null : in, cm);
+					} catch (ParseException e) {
+						throw new BadRequest(e,
+							"Could not convert request body content to class type ''{0}'' using parser ''{1}''.",
+							cm, partParser.getClass().getName()
+						);
+					}
+				} else if (cm.hasStringTransform()) {
+					return cm.getStringTransform().transform(asString());
+				}
+			}
 			
 			throw new UnsupportedMediaType(
 				"Unsupported media-type in request header ''Content-Type'': ''{0}''\n\tSupported media-types: {1}",
@@ -453,7 +482,7 @@ public class RequestBody {
 	private Encoder getEncoder() throws UnsupportedMediaType {
 		if (encoder == null) {
 			String ce = req.getHeader("content-encoding");
-			if (! isEmpty(ce)) {
+			if (isNotEmpty(ce)) {
 				ce = ce.trim();
 				encoder = encoders.getEncoder(ce);
 				if (encoder == null)
@@ -481,4 +510,17 @@ public class RequestBody {
 	public int getContentLength() {
 		return contentLength == 0 ? req.getRawContentLength() : contentLength;
 	}
+	
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Helper methods
+	//-----------------------------------------------------------------------------------------------------------------
+	
+	private <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
+		return beanSession.getClassMeta(type, args);
+	}
+
+	private <T> ClassMeta<T> getClassMeta(Class<T> type) {
+		return beanSession.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 242b60d..5666290 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
@@ -22,6 +22,7 @@ import javax.servlet.http.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.oapi.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
@@ -246,7 +247,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * @throws ParseException
 	 */
 	public <T> T get(String name, Class<T> type) throws ParseException {
-		return get(null, name, type);
+		return getInner(null, null, name, null, getClassMeta(type));
 	}
 
 	/**
@@ -255,14 +256,19 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
 	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
+	 * @param schema 
+	 * 	The schema object that defines the format of the input.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the parser.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part parser is not a subclass of {@link OapiPartParser}.
 	 * @param name The parameter name.
 	 * @param type The class type to convert the parameter value to.
 	 * @param <T> The class type to convert the parameter value to.
 	 * @return The parameter value converted to the specified class type.
 	 * @throws ParseException
 	 */
-	public <T> T get(HttpPartParser parser, String name, Class<T> type) throws ParseException {
-		return parse(parser, name, getClassMeta(type));
+	public <T> T get(HttpPartParser parser, HttpPartSchema schema, String name, Class<T> type) throws ParseException {
+		return getInner(parser, schema, name, null, getClassMeta(type));
 	}
 
 	/**
@@ -276,7 +282,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * @throws ParseException
 	 */
 	public <T> T get(String name, T def, Class<T> type) throws ParseException {
-		return get(null, name, def, type);
+		return getInner(null, null, name, def, getClassMeta(type));
 	}
 
 	/**
@@ -285,6 +291,11 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
 	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
+	 * @param schema 
+	 * 	The schema object that defines the format of the input.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the parser.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part parser is not a subclass of {@link OapiPartParser}.
 	 * @param name The parameter name.
 	 * @param def The default value if the parameter was not specified or is <jk>null</jk>.
 	 * @param type The class type to convert the parameter value to.
@@ -292,8 +303,8 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * @return The parameter value converted to the specified class type.
 	 * @throws ParseException
 	 */
-	public <T> T get(HttpPartParser parser, String name, T def, Class<T> type) throws ParseException {
-		return parse(parser, name, def, getClassMeta(type));
+	public <T> T get(HttpPartParser parser, HttpPartSchema schema, String name, T def, Class<T> type) throws ParseException {
+		return getInner(parser, schema, name, def, getClassMeta(type));
 	}
 
 	/**
@@ -309,7 +320,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * @throws ParseException
 	 */
 	public <T> T getAll(String name, Class<T> type) throws ParseException {
-		return getAll(null, name, type);
+		return getAllInner(null, null, name, null, getClassMeta(type));
 	}
 
 	/**
@@ -321,13 +332,18 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
 	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
+	 * @param schema 
+	 * 	The schema object that defines the format of the input.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the parser.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part parser is not a subclass of {@link OapiPartParser}.
 	 * @param name The parameter name.
 	 * @param type The class type to convert the parameter value to.
 	 * @return The parameter value converted to the specified class type.
 	 * @throws ParseException
 	 */
-	public <T> T getAll(HttpPartParser parser, String name, Class<T> type) throws ParseException {
-		return parseAll(parser, name, getClassMeta(type));
+	public <T> T getAll(HttpPartParser parser, HttpPartSchema schema, String name, Class<T> type) throws ParseException {
+		return getAllInner(parser, schema, name, null, getClassMeta(type));
 	}
 
 	/**
@@ -376,7 +392,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * @throws ParseException
 	 */
 	public <T> T get(String name, Type type, Type...args) throws ParseException {
-		return get(null, name, type, args);
+		return getInner(null, null, name, null, this.<T>getClassMeta(type, args));
 	}
 
 	/**
@@ -385,6 +401,11 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
 	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
+	 * @param schema 
+	 * 	The schema object that defines the format of the input.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the parser.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part parser is not a subclass of {@link OapiPartParser}.
 	 * @param name The parameter name.
 	 * @param type
 	 * 	The type of object to create.
@@ -396,8 +417,56 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * @return The parameter value converted to the specified class type.
 	 * @throws ParseException
 	 */
-	public <T> T get(HttpPartParser parser, String name, Type type, Type...args) throws ParseException {
-		return (T)parse(parser, name, getClassMeta(type, args));
+	public <T> T get(HttpPartParser parser, HttpPartSchema schema, String name, Type type, Type...args) throws ParseException {
+		return getInner(parser, schema, name, null, this.<T>getClassMeta(type, args));
+	}
+
+	/**
+	 * Same as {@link #get(String, Class)} except returns a default value if not found.
+	 * 
+	 * @param name The parameter name.
+	 * @param type
+	 * 	The type of object to create.
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
+	 * @param args
+	 * 	The type arguments of the class if it's a collection or map.
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
+	 * 	<br>Ignored if the main type is not a map or collection.
+	 * @param def The default value if the parameter was not specified or is <jk>null</jk>.
+	 * @param <T> The class type to convert the parameter value to.
+	 * @return The parameter value converted to the specified class type.
+	 * @throws ParseException
+	 */
+	public <T> T get(String name, T def, Type type, Type...args) throws ParseException {
+		return getInner(null, null, name, def, this.<T>getClassMeta(type, args));
+	}
+
+	/**
+	 * Same as {@link #get(String, Object, Type, Type...)} but allows you to override the part parser.
+	 * 
+	 * @param parser
+	 * 	The parser to use for parsing the string value.
+	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
+	 * @param schema 
+	 * 	The schema object that defines the format of the input.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the parser.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part parser is not a subclass of {@link OapiPartParser}.
+	 * @param name The parameter name.
+	 * @param type
+	 * 	The type of object to create.
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
+	 * @param args
+	 * 	The type arguments of the class if it's a collection or map.
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
+	 * 	<br>Ignored if the main type is not a map or collection.
+	 * @param def The default value if the parameter was not specified or is <jk>null</jk>.
+	 * @param <T> The class type to convert the parameter value to.
+	 * @return The parameter value converted to the specified class type.
+	 * @throws ParseException
+	 */
+	public <T> T get(HttpPartParser parser, HttpPartSchema schema, String name, T def, Type type, Type...args) throws ParseException {
+		return getInner(parser, schema, name, def, this.<T>getClassMeta(type, args));
 	}
 
 	/**
@@ -419,7 +488,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * @throws ParseException
 	 */
 	public <T> T getAll(String name, Type type, Type...args) throws ParseException {
-		return getAll(null, name, type, args);
+		return getAllInner(null, null, name, null, this.<T>getClassMeta(type, args));
 	}
 	
 	/**
@@ -428,6 +497,11 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
 	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
+	 * @param schema 
+	 * 	The schema object that defines the format of the input.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the parser.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part parser is not a subclass of {@link OapiPartParser}.
 	 * @param name The parameter name.
 	 * @param type
 	 * 	The type of object to create.
@@ -439,45 +513,34 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * @return The parameter value converted to the specified class type.
 	 * @throws ParseException
 	 */
-	public <T> T getAll(HttpPartParser parser, String name, Type type, Type...args) throws ParseException {
-		return (T)parseAll(parser, name, getClassMeta(type, args));
+	public <T> T getAll(HttpPartParser parser, HttpPartSchema schema, String name, Type type, Type...args) throws ParseException {
+		return getAllInner(parser, schema, name, null, this.<T>getClassMeta(type, args));
 	}
 	
-
 	/* Workhorse method */
-	<T> T parse(HttpPartParser parser, String name, T def, ClassMeta<T> cm) throws ParseException {
-		String val = getString(name);
-		if (val == null)
-			return def;
-		return parseValue(parser, val, cm);
-	}
-
-	/* Workhorse method */
-	<T> T parse(HttpPartParser parser, String name, ClassMeta<T> cm) throws ParseException {
-		String val = getString(name);
-		if (cm.isPrimitive() && (val == null || val.isEmpty()))
-			return cm.getPrimitiveDefault();
-		return parseValue(parser, val, cm);
+	private <T> T getInner(HttpPartParser parser, HttpPartSchema schema, String name, T def, ClassMeta<T> cm) throws ParseException {
+		T t = parse(parser, schema, getString(name), cm);
+		return (t == null ? def : t);
 	}
 
 	/* Workhorse method */
 	@SuppressWarnings("rawtypes")
-	<T> T parseAll(HttpPartParser parser, String name, ClassMeta<T> cm) throws ParseException {
+	<T> T getAllInner(HttpPartParser parser, HttpPartSchema schema, String name, T def, ClassMeta<T> cm) throws ParseException {
 		String[] p = get(name);
-		if (p == null)
-			return null;
-		if (parser == null)
-			parser = this.parser;
+		if (p == null) 
+			return def;
+		if (schema == null)
+			schema = HttpPartSchema.DEFAULT;
 		if (cm.isArray()) {
 			List c = new ArrayList();
 			for (int i = 0; i < p.length; i++)
-				c.add(parseValue(parser, p[i], cm.getElementType()));
+				c.add(parse(parser, schema.getItems(), p[i], cm.getElementType()));
 			return (T)toArray(c, cm.getElementType().getInnerClass());
 		} else if (cm.isCollection()) {
 			try {
 				Collection c = (Collection)(cm.canCreateNewInstance() ? cm.newInstance() : new ObjectList());
 				for (int i = 0; i < p.length; i++)
-					c.add(parseValue(parser, p[i], cm.getElementType()));
+					c.add(parse(parser, schema.getItems(), p[i], cm.getElementType()));
 				return (T)c;
 			} catch (ParseException e) {
 				throw e;
@@ -489,14 +552,10 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 		throw new ParseException("Invalid call to getParameters(String, ClassMeta).  Class type must be a Collection or array.");
 	}
 
-	private <T> T parseValue(HttpPartParser parser, String val, ClassMeta<T> c) throws ParseException {
-		try {
-			if (parser == null)
-				parser = this.parser;
-			return parser.parse(HttpPartType.FORMDATA, val, c);
-		} catch (Exception e) {
-			throw new ParseException(e);
-		}
+	private <T> T parse(HttpPartParser parser, HttpPartSchema schema, String val, ClassMeta<T> c) throws ParseException {
+		if (parser == null)
+			parser = this.parser;
+		return parser.parse(HttpPartType.FORMDATA, schema, val, c);
 	}
 
 	/**
@@ -515,16 +574,20 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 		return JsonSerializer.DEFAULT_LAX.toString(m);
 	}
 
-	private ClassMeta<?> getClassMeta(Type type, Type...args) {
+	@Override /* Object */
+	public String toString() {
+		return toString(false);
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Helper methods
+	//-----------------------------------------------------------------------------------------------------------------
+	
+	private <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
 		return beanSession.getClassMeta(type, args);
 	}
 
 	private <T> ClassMeta<T> getClassMeta(Class<T> type) {
 		return beanSession.getClassMeta(type);
 	}
-
-	@Override /* Object */
-	public String toString() {
-		return toString(false);
-	}
 }
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 44f780e..eec09cc 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
@@ -22,6 +22,7 @@ import org.apache.juneau.*;
 import org.apache.juneau.http.*;
 import org.apache.juneau.http.Date;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.oapi.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
@@ -252,7 +253,7 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	 * @throws ParseException 
 	 */
 	public <T> T get(String name, Class<T> type) throws ParseException {
-		return get(parser, name, null, type);
+		return getInner(null, null, name, null, getClassMeta(type));
 	}
 
 	/**
@@ -261,14 +262,19 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	 * @param parser
 	 * 	The parser to use for parsing the string header.
 	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
+	 * @param schema 
+	 * 	The schema object that defines the format of the input.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the parser.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part parser is not a subclass of {@link OapiPartParser}.
 	 * @param name The HTTP header name.
 	 * @param type The class type to convert the header value to.
 	 * @param <T> The class type to convert the header value to.
 	 * @return The parameter value converted to the specified class type.
 	 * @throws ParseException 
 	 */
-	public <T> T get(HttpPartParser parser, String name, Class<T> type) throws ParseException {
-		return get(parser, name, null, type);
+	public <T> T get(HttpPartParser parser, HttpPartSchema schema, String name, Class<T> type) throws ParseException {
+		return getInner(parser, schema, name, null, getClassMeta(type));
 	}
 
 	/**
@@ -282,7 +288,7 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	 * @throws ParseException 
 	 */
 	public <T> T get(String name, T def, Class<T> type) throws ParseException {
-		return get(parser, name, def, type);
+		return getInner(null, null, name, def, getClassMeta(type));
 	}
 
 	/**
@@ -291,6 +297,11 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	 * @param parser
 	 * 	The parser to use for parsing the string header.
 	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
+	 * @param schema 
+	 * 	The schema object that defines the format of the input.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the parser.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part parser is not a subclass of {@link OapiPartParser}.
 	 * @param name The HTTP header name.
 	 * @param def The default value if the header was not specified or is <jk>null</jk>.
 	 * @param type The class type to convert the header value to.
@@ -298,13 +309,8 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	 * @return The parameter value converted to the specified class type.
 	 * @throws ParseException 
 	 */
-	public <T> T get(HttpPartParser parser, String name, T def, Class<T> type) throws ParseException {
-		String s = getString(name);
-		if (s == null)
-			return def;
-		if (parser == null)
-			parser = this.parser;
-		return parser.parse(HttpPartType.HEADER, s, getClassMeta(type));
+	public <T> T get(HttpPartParser parser, HttpPartSchema schema, String name, T def, Class<T> type) throws ParseException {
+		return getInner(parser, schema, name, def, getClassMeta(type));
 	}
 
 	/**
@@ -347,7 +353,7 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	 * @throws ParseException If the header could not be converted to the specified type.
 	 */
 	public <T> T get(String name, Type type, Type...args) throws ParseException {
-		return get(null, name, type, args);
+		return getInner(null, null, name, null, this.<T>getClassMeta(type, args));
 	}
 
 	/**
@@ -356,6 +362,11 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	 * @param parser
 	 * 	The parser to use for parsing the string header.
 	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
+	 * @param schema 
+	 * 	The schema object that defines the format of the input.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the parser.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part parser is not a subclass of {@link OapiPartParser}.
 	 * @param name 
 	 * 	The HTTP header name.
 	 * @param type
@@ -369,14 +380,21 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	 * @return The parameter value converted to the specified class type.
 	 * @throws ParseException If the header could not be converted to the specified type.
 	 */
-	@SuppressWarnings("unchecked")
-	public <T> T get(HttpPartParser parser, String name, Type type, Type...args) throws ParseException {
-		String s = getString(name);
-		if (s == null)
-			return null;
+	public <T> T get(HttpPartParser parser, HttpPartSchema schema, String name, Type type, Type...args) throws ParseException {
+		return getInner(parser, schema, name, null, this.<T>getClassMeta(type, args));
+	}
+	
+	/* Workhorse method */
+	private <T> T getInner(HttpPartParser parser, HttpPartSchema schema, String name, T def, ClassMeta<T> cm) throws ParseException {
+		T t = parse(parser, schema, getString(name), cm);
+		return (t == null ? def : t);
+	}
+
+	/* Workhorse method */
+	private <T> T parse(HttpPartParser parser, HttpPartSchema schema, String val, ClassMeta<T> cm) throws ParseException {
 		if (parser == null)
 			parser = this.parser;
-		return (T)parser.parse(HttpPartType.HEADER, s, getClassMeta(type, args));
+		return parser.parse(HttpPartType.HEADER, schema, val, cm);
 	}
 
 	/**
@@ -916,16 +934,20 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 		return JsonSerializer.DEFAULT_LAX.toString(m);
 	}
 	
-	private ClassMeta<?> getClassMeta(Type type, Type...args) {
+	@Override /* Object */
+	public String toString() {
+		return toString(false);
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Helper methods
+	//-----------------------------------------------------------------------------------------------------------------
+	
+	private <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
 		return beanSession.getClassMeta(type, args);
 	}
 
 	private <T> ClassMeta<T> getClassMeta(Class<T> type) {
 		return beanSession.getClassMeta(type);
 	}
-
-	@Override /* Object */
-	public String toString() {
-		return toString(false);
-	}
 }
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 a32f216..6974649 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
@@ -19,6 +19,7 @@ import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.oapi.*;
 import org.apache.juneau.parser.*;
 
 /**
@@ -32,7 +33,6 @@ import org.apache.juneau.parser.*;
  * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestPathMatch">Overview &gt; juneau-rest-server &gt; RequestPathMatch</a>
  * </ul>
  */
-@SuppressWarnings("unchecked")
 public class RequestPathMatch extends TreeMap<String,String> {
 	private static final long serialVersionUID = 1L;
 
@@ -82,7 +82,7 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	 * @throws ParseException
 	 */
 	public String getString(String name) throws ParseException {
-		return parse(parser, name, beanSession.string());
+		return getInner(parser, null, name, null, beanSession.string());
 	}
 
 	/**
@@ -93,7 +93,7 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	 * @throws ParseException
 	 */
 	public int getInt(String name) throws ParseException {
-		return parse(parser, name, beanSession.getClassMeta(int.class));
+		return getInner(parser, null, name, null, getClassMeta(int.class));
 	}
 
 	/**
@@ -104,7 +104,7 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	 * @throws ParseException
 	 */
 	public boolean getBoolean(String name) throws ParseException {
-		return parse(parser, name, beanSession.getClassMeta(boolean.class));
+		return getInner(null, null, name, null, getClassMeta(boolean.class));
 	}
 
 	/**
@@ -140,7 +140,7 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	 * @throws ParseException
 	 */
 	public <T> T get(String name, Class<T> type) throws ParseException {
-		return get(parser, name, type);
+		return getInner(null, null, name, null, this.<T>getClassMeta(type));
 	}
 
 	/**
@@ -149,14 +149,19 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
 	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
+	 * @param schema 
+	 * 	The schema object that defines the format of the input.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the parser.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part parser is not a subclass of {@link OapiPartParser}.
 	 * @param name The attribute name.
 	 * @param type The class type to convert the attribute value to.
 	 * @param <T> The class type to convert the attribute value to.
 	 * @return The attribute value converted to the specified class type.
 	 * @throws ParseException
 	 */
-	public <T> T get(HttpPartParser parser, String name, Class<T> type) throws ParseException {
-		return parse(parser, name, beanSession.getClassMeta(type));
+	public <T> T get(HttpPartParser parser, HttpPartSchema schema, String name, Class<T> type) throws ParseException {
+		return getInner(parser, schema, name, null, this.<T>getClassMeta(type));
 	}
 
 	/**
@@ -209,7 +214,7 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	 * @throws ParseException
 	 */
 	public <T> T get(String name, Type type, Type...args) throws ParseException {
-		return get(parser, name, type, args);
+		return getInner(null, null, name, null, this.<T>getClassMeta(type, args));
 	}
 
 	/**
@@ -218,6 +223,11 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
 	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
+	 * @param schema 
+	 * 	The schema object that defines the format of the input.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the parser.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part parser is not a subclass of {@link OapiPartParser}.
 	 * @param name The attribute name.
 	 * @param type
 	 * 	The type of object to create.
@@ -230,22 +240,21 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	 * @return The attribute value converted to the specified class type.
 	 * @throws ParseException
 	 */
-	public <T> T get(HttpPartParser parser, String name, Type type, Type...args) throws ParseException {
-		return (T)parse(parser, name, beanSession.getClassMeta(type, args));
+	public <T> T get(HttpPartParser parser, HttpPartSchema schema, String name, Type type, Type...args) throws ParseException {
+		return getInner(parser, schema, name, null, this.<T>getClassMeta(type, args));
 	}
-	
-	
+
+	/* Workhorse method */
+	private <T> T getInner(HttpPartParser parser, HttpPartSchema schema, String name, T def, ClassMeta<T> cm) throws ParseException {
+		T t = parse(parser, schema, get(name), cm);
+		return (t == null ? def : t);
+	}
+
 	/* Workhorse method */
-	<T> T parse(HttpPartParser parser, String name, ClassMeta<T> cm) throws ParseException {
+	private <T> T parse(HttpPartParser parser, HttpPartSchema schema, String val, ClassMeta<T> cm) throws ParseException {
 		if (parser == null)
 			parser = this.parser;
-		Object attr = get(name);
-		T t = null;
-		if (attr != null)
-			t = parser.parse(HttpPartType.PATH, attr.toString(), cm);
-		if (t == null && cm.isPrimitive())
-			return cm.getPrimitiveDefault();
-		return t;
+		return parser.parse(HttpPartType.PATH, schema, val, cm);
 	}
 
 	/**
@@ -320,4 +329,16 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	public String getPattern() {
 		return pattern;
 	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Helper methods
+	//-----------------------------------------------------------------------------------------------------------------
+	
+	private <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
+		return beanSession.getClassMeta(type, args);
+	}
+
+	private <T> ClassMeta<T> getClassMeta(Class<T> type) {
+		return beanSession.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 ff949fa..5e358eb 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
@@ -22,6 +22,7 @@ import javax.servlet.http.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.oapi.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
@@ -245,7 +246,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @throws ParseException
 	 */
 	public <T> T get(String name, Class<T> type) throws ParseException {
-		return get(null, name, type);
+		return getInner(null, null, name, null, getClassMeta(type));
 	}
 
 	/**
@@ -254,14 +255,19 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
 	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
+	 * @param schema 
+	 * 	The schema object that defines the format of the input.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the parser.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part parser is not a subclass of {@link OapiPartParser}.
 	 * @param name The parameter name.
 	 * @param type The class type to convert the parameter value to.
 	 * @param <T> The class type to convert the parameter value to.
 	 * @return The parameter value converted to the specified class type.
 	 * @throws ParseException
 	 */
-	public <T> T get(HttpPartParser parser, String name, Class<T> type) throws ParseException {
-		return get(parser, name, getClassMeta(type));
+	public <T> T get(HttpPartParser parser, HttpPartSchema schema, String name, Class<T> type) throws ParseException {
+		return getInner(parser, schema, name, null, getClassMeta(type));
 	}
 
 	/**
@@ -275,7 +281,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @throws ParseException
 	 */
 	public <T> T get(String name, T def, Class<T> type) throws ParseException {
-		return get(null, name, def, type);
+		return getInner(null, null, name, def, getClassMeta(type));
 	}
 
 	/**
@@ -284,6 +290,11 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
 	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
+	 * @param schema 
+	 * 	The schema object that defines the format of the input.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the parser.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part parser is not a subclass of {@link OapiPartParser}.
 	 * @param name The parameter name.
 	 * @param def The default value if the parameter was not specified or is <jk>null</jk>.
 	 * @param type The class type to convert the parameter value to.
@@ -291,8 +302,8 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @return The parameter value converted to the specified class type.
 	 * @throws ParseException
 	 */
-	public <T> T get(HttpPartParser parser, String name, T def, Class<T> type) throws ParseException {
-		return get(parser, name, def, getClassMeta(type));
+	public <T> T get(HttpPartParser parser, HttpPartSchema schema, String name, T def, Class<T> type) throws ParseException {
+		return getInner(parser, schema, name, def, getClassMeta(type));
 	}
 
 	/**
@@ -342,7 +353,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @throws ParseException
 	 */
 	public <T> T get(String name, Type type, Type...args) throws ParseException {
-		return get((HttpPartParser)null, name, type, args);
+		return getInner(null, null, name, null, (ClassMeta<T>)getClassMeta(type, args));
 	}
 
 	/**
@@ -351,7 +362,11 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
 	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
-	 * 
+	 * @param schema 
+	 * 	The schema object that defines the format of the input.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the parser.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part parser is not a subclass of {@link OapiPartParser}.
 	 * @param name The parameter name.
 	 * @param type
 	 * 	The type of object to create.
@@ -364,8 +379,8 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @return The parameter value converted to the specified class type.
 	 * @throws ParseException
 	 */
-	public <T> T get(HttpPartParser parser, String name, Type type, Type...args) throws ParseException {
-		return (T)parse(parser, name, getClassMeta(type, args));
+	public <T> T get(HttpPartParser parser, HttpPartSchema schema, String name, Type type, Type...args) throws ParseException {
+		return getInner(parser, schema, name, null, (ClassMeta<T>)getClassMeta(type, args));
 	}
 
 	/**
@@ -384,8 +399,8 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @return The parameter value converted to the specified class type.
 	 * @throws ParseException
 	 */
-	public <T> T get(String name, Object def, Type type, Type...args) throws ParseException {
-		return get(null, name, def, type, args);
+	public <T> T get(String name, T def, Type type, Type...args) throws ParseException {
+		return getInner(null, null, name, def, (ClassMeta<T>)getClassMeta(type, args));
 	}
 
 	/**
@@ -394,6 +409,11 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
 	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
+	 * @param schema 
+	 * 	The schema object that defines the format of the input.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the parser.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part parser is not a subclass of {@link OapiPartParser}.
 	 * @param name The parameter name.
 	 * @param type
 	 * 	The type of object to create.
@@ -407,8 +427,8 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @return The parameter value converted to the specified class type.
 	 * @throws ParseException
 	 */
-	public <T> T get(HttpPartParser parser, String name, Object def, Type type, Type...args) throws ParseException {
-		return (T)parse(parser, name, def, getClassMeta(type, args));
+	public <T> T get(HttpPartParser parser, HttpPartSchema schema, String name, T def, Type type, Type...args) throws ParseException {
+		return getInner(parser, schema, name, def, (ClassMeta<T>)getClassMeta(type, args));
 	}
 
 	/**
@@ -425,7 +445,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @throws ParseException
 	 */
 	public <T> T getAll(String name, Class<T> c) throws ParseException {
-		return getAll(name, beanSession.getClassMeta(c));
+		return getAllInner(null, null, name, null, beanSession.getClassMeta(c));
 	}
 
 	/**
@@ -448,7 +468,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @throws ParseException
 	 */
 	public <T> T getAll(String name, Type type, Type...args) throws ParseException {
-		return getAll(null, name, type, args);
+		return getAllInner(null, null, name, null, (ClassMeta<T>)getClassMeta(type, args));
 	}
 
 	/**
@@ -457,6 +477,11 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
 	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
+	 * @param schema 
+	 * 	The schema object that defines the format of the input.
+	 * 	<br>If <jk>null</jk>, defaults to the schema defined on the parser.
+	 * 	<br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.  
+	 * 	<br>Ignored if the part parser is not a subclass of {@link OapiPartParser}.
 	 * @param name The query parameter name.
 	 * @param type
 	 * 	The type of object to create.
@@ -469,8 +494,8 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @return The query parameter value converted to the specified class type.
 	 * @throws ParseException
 	 */
-	public <T> T getAll(HttpPartParser parser, String name, Type type, Type...args) throws ParseException {
-		return (T)parseAll(parser, name, getClassMeta(type, args));
+	public <T> T getAll(HttpPartParser parser, HttpPartSchema schema, String name, Type type, Type...args) throws ParseException {
+		return getAllInner(parser, schema, name, null, (ClassMeta<T>)getClassMeta(type, args));
 	}
 
 	/**
@@ -552,37 +577,29 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	}
 
 	/* Workhorse method */
-	private <T> T parse(HttpPartParser parser, String name, Object def, ClassMeta<T> cm) throws ParseException {
-		String val = getString(name);
-		if (val == null)
-			return (T)def;
-		return parseValue(parser, val, cm);
-	}
-
-	/* Workhorse method */
-	private <T> T parse(HttpPartParser parser, String name, ClassMeta<T> cm) throws ParseException {
-		String val = getString(name);
-		if (cm.isPrimitive() && (val == null || val.isEmpty()))
-			return cm.getPrimitiveDefault();
-		return parseValue(parser, val, cm);
+	private <T> T getInner(HttpPartParser parser, HttpPartSchema schema, String name, T def, ClassMeta<T> cm) throws ParseException {
+		T t = parse(parser, schema, getString(name), cm);
+		return (t == null ? def : t);
 	}
 
 	/* Workhorse method */
 	@SuppressWarnings("rawtypes")
-	private <T> T parseAll(HttpPartParser parser, String name, ClassMeta<T> cm) throws ParseException {
+	private <T> T getAllInner(HttpPartParser parser, HttpPartSchema schema, String name, T def, ClassMeta<T> cm) throws ParseException {
 		String[] p = get(name);
 		if (p == null)
-			return null;
+			return def;
+		if (schema == null)
+			schema = HttpPartSchema.DEFAULT;
 		if (cm.isArray()) {
 			List c = new ArrayList();
 			for (int i = 0; i < p.length; i++)
-				c.add(parseValue(parser, p[i], cm.getElementType()));
+				c.add(parse(parser, schema.getItems(), p[i], cm.getElementType()));
 			return (T)toArray(c, cm.getElementType().getInnerClass());
 		} else if (cm.isCollection()) {
 			try {
 				Collection c = (Collection)(cm.canCreateNewInstance() ? cm.newInstance() : new ObjectList());
 				for (int i = 0; i < p.length; i++)
-					c.add(parseValue(parser, p[i], cm.getElementType()));
+					c.add(parse(parser, schema.getItems(), p[i], cm.getElementType()));
 				return (T)c;
 			} catch (ParseException e) {
 				throw e;
@@ -594,10 +611,10 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 		throw new ParseException("Invalid call to getQueryParameters(String, ClassMeta).  Class type must be a Collection or array.");
 	}
 
-	private <T> T parseValue(HttpPartParser parser, String val, ClassMeta<T> c) throws ParseException {
+	private <T> T parse(HttpPartParser parser, HttpPartSchema schema, String val, ClassMeta<T> c) throws ParseException {
 		if (parser == null)
 			parser = this.parser;
-		return parser.parse(HttpPartType.QUERY, val, c);
+		return parser.parse(HttpPartType.QUERY, schema, val, c);
 	}
 
 	/**
@@ -635,16 +652,20 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 		return sb.toString();
 	}
 
-	private ClassMeta<?> getClassMeta(Type type, Type...args) {
+	@Override /* Object */
+	public String toString() {
+		return toString(false);
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Helper methods
+	//-----------------------------------------------------------------------------------------------------------------
+	
+	private <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
 		return beanSession.getClassMeta(type, args);
 	}
 
 	private <T> ClassMeta<T> getClassMeta(Class<T> type) {
 		return beanSession.getClassMeta(type);
 	}
-
-	@Override /* Object */
-	public String toString() {
-		return toString(false);
-	}
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 5a1c34a..2e58d7c 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -17,7 +17,6 @@ import static org.apache.juneau.internal.ClassUtils.*;
 import static org.apache.juneau.internal.CollectionUtils.*;
 import static org.apache.juneau.internal.IOUtils.*;
 import static org.apache.juneau.internal.StringUtils.*;
-import static org.apache.juneau.internal.ObjectUtils.*;
 
 import java.io.*;
 import java.lang.annotation.*;
@@ -39,6 +38,8 @@ import org.apache.juneau.html.*;
 import org.apache.juneau.htmlschema.*;
 import org.apache.juneau.http.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.oapi.*;
+import org.apache.juneau.httppart.uon.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.jsonschema.*;
@@ -1735,7 +1736,7 @@ public final class RestContext extends BeanContext {
 	 * <ul>
 	 * 	<li><b>Name:</b>  <js>"RestContext.partParser.o"</js>
 	 * 	<li><b>Data type:</b>  <code>{@link HttpPartParser} | Class&lt;? <jk>extends</jk> {@link HttpPartParser}&gt;</code>
-	 * 	<li><b>Default:</b>  {@link UonPartParser}
+	 * 	<li><b>Default:</b>  {@link OapiPartSerializer}
 	 * 	<li><b>Session-overridable:</b>  <jk>false</jk>
 	 * 	<li><b>Annotations:</b> 
 	 * 		<ul>
@@ -1753,7 +1754,7 @@ public final class RestContext extends BeanContext {
 	 * Specifies the {@link HttpPartParser} to use for parsing headers, query/form parameters, and URI parts.
 	 * 
 	 * <p>
-	 * The default value is {@link UonPartParser} which allows for both plain-text and URL-Encoded-Object-Notation values.
+	 * The default value is {@link OapiPartParser} which allows for both plain-text and URL-Encoded-Object-Notation values.
 	 * <br>If your parts contain text that can be confused with UON (e.g. <js>"(foo)"</js>), you can switch to 
 	 * {@link SimplePartParser} which treats everything as plain text.
 	 * 
@@ -1803,7 +1804,7 @@ public final class RestContext extends BeanContext {
 	 * <ul>
 	 * 	<li><b>Name:</b>  <js>"RestContext.partSerializer.o"</js>
 	 * 	<li><b>Data type:</b>  <code>{@link HttpPartSerializer} | Class&lt;? <jk>extends</jk> {@link HttpPartSerializer}&gt;</code>
-	 * 	<li><b>Default:</b>  {@link SimpleUonPartSerializer}
+	 * 	<li><b>Default:</b>  {@link OapiPartSerializer}
 	 * 	<li><b>Session-overridable:</b>  <jk>false</jk>
 	 * 	<li><b>Annotations:</b> 
 	 * 		<ul>
@@ -1821,12 +1822,14 @@ public final class RestContext extends BeanContext {
 	 * Specifies the {@link HttpPartSerializer} to use for serializing headers, query/form parameters, and URI parts.
 	 * 
 	 * <p>
-	 * The default value is {@link SimpleUonPartSerializer} which serializes UON notation for beans and maps, and
+	 * The default value is {@link OapiPartSerializer} which serializes based on OpenAPI rules, but defaults to UON notation for beans and maps, and
 	 * plain text for everything else.
 	 * <br>Other options include:
 	 * <ul>
 	 * 	<li class='jc'>{@link SimplePartSerializer} - Always serializes to plain text.
 	 * 	<li class='jc'>{@link UonPartSerializer} - Always serializers to UON.
+	 * 	<li class='jc'>{@link SimpleUonPartSerializer} - Serializes to UON notation for beans and maps, and
+	 * 		plain text for everything else..
 	 * </ul>
 	 * 
 	 * <h5 class='section'>Example:</h5>
@@ -2919,8 +2922,8 @@ public final class RestContext extends BeanContext {
 			properties = builder.properties;
 			serializers = SerializerGroup.create().append(getInstanceArrayProperty(REST_serializers, Serializer.class, new Serializer[0], true, resource, ps)).build();
 			parsers = ParserGroup.create().append(getInstanceArrayProperty(REST_parsers, Parser.class, new Parser[0], true, resource, ps)).build();
-			partSerializer = getInstanceProperty(REST_partSerializer, HttpPartSerializer.class, SimpleUonPartSerializer.class, true, resource, ps);
-			partParser = getInstanceProperty(REST_partSerializer, HttpPartParser.class, UonPartParser.class, true, resource, ps);
+			partSerializer = getInstanceProperty(REST_partSerializer, HttpPartSerializer.class, OapiPartSerializer.class, true, resource, ps);
+			partParser = getInstanceProperty(REST_partSerializer, HttpPartParser.class, OapiPartParser.class, true, resource, ps);
 			jsonSchemaSerializer = new JsonSchemaSerializer(ps);
 			encoders = new EncoderGroupBuilder().append(getInstanceArrayProperty(REST_encoders, Encoder.class, new Encoder[0], true, resource, ps)).build();
 			beanContext = BeanContext.create().apply(ps).build();
@@ -3956,7 +3959,7 @@ public final class RestContext extends BeanContext {
 	 * @return <jk>true</jk> if this resource allows the specified method to be overridden.
 	 */
 	public boolean allowMethodParam(String m) {
-		return (! isEmpty(m) && (allowedMethodParams.contains(m) || allowedMethodParams.contains("*")));
+		return (isNotEmpty(m) && (allowedMethodParams.contains(m) || allowedMethodParams.contains("*")));
 	}
 
 	/**
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
index 4ca2923..51569d8 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
@@ -33,6 +33,7 @@ import org.apache.juneau.config.vars.*;
 import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.oapi.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.annotation.*;
@@ -1280,7 +1281,7 @@ public class RestContextBuilder extends BeanContextBuilder implements ServletCon
 	 * 
 	 * @param value 
 	 * 	The new value for this setting.
-	 * 	<br>The default is {@link UonPartParser}.
+	 * 	<br>The default is {@link OapiPartParser}.
 	 * @return This object (for method chaining).
 	 */
 	public RestContextBuilder partParser(Class<? extends HttpPartParser> value) {
@@ -1300,7 +1301,7 @@ public class RestContextBuilder extends BeanContextBuilder implements ServletCon
 	 * 
 	 * @param value 
 	 * 	The new value for this setting.
-	 * 	<br>The default is {@link UonPartParser}.
+	 * 	<br>The default is {@link OapiPartParser}.
 	 * @return This object (for method chaining).
 	 */
 	public RestContextBuilder partParser(HttpPartParser value) {
@@ -1320,7 +1321,7 @@ public class RestContextBuilder extends BeanContextBuilder implements ServletCon
 	 * 
 	 * @param value 
 	 * 	The new value for this setting.
-	 * 	<br>The default is {@link SimpleUonPartSerializer}.
+	 * 	<br>The default is {@link OapiPartSerializer}.
 	 * @return This object (for method chaining).
 	 */
 	public RestContextBuilder partSerializer(Class<? extends HttpPartSerializer> value) {
@@ -1340,7 +1341,7 @@ public class RestContextBuilder extends BeanContextBuilder implements ServletCon
 	 * 
 	 * @param value 
 	 * 	The new value for this setting.
-	 * 	<br>The default is {@link SimpleUonPartSerializer}.
+	 * 	<br>The default is {@link OapiPartSerializer}.
 	 * @return This object (for method chaining).
 	 */
 	public RestContextBuilder partSerializer(HttpPartSerializer value) {
@@ -1698,7 +1699,7 @@ public class RestContextBuilder extends BeanContextBuilder implements ServletCon
 	 * @return This object (for method chaining).
 	 */
 	public RestContextBuilder staticFiles(Class<?> baseClass, String mappingString) {
-		if (! isEmpty(mappingString))
+		if (isNotEmpty(mappingString))
 			staticFiles(new StaticFileMapping(baseClass, mappingString));
 		return this;
 	}
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 bd3956b..dfb194e 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
@@ -548,9 +548,13 @@ class RestParamDefaults {
 	//-------------------------------------------------------------------------------------------------------------------
 
 	static final class PathObject extends RestMethodParam {
+		private final HttpPartParser partParser;
+		private final HttpPartSchema schema;
 
 		protected PathObject(Method method, Path a, Type type, PropertyStore ps, RestMethodParam existing) {
 			super(PATH, method, firstNonEmpty(existing == null ? null : existing.name, a.name(), a.value()), type, getMetaData(a, castOrNull(existing, PathObject.class)));
+			this.partParser = a.parser() == HttpPartParser.Null.class ? null : ClassUtils.newInstance(HttpPartParser.class, a.parser(), true, ps);
+			this.schema = getSchema(metaData, method, "@Path");
 		}
 
 		@Override /* RestMethodParam */
@@ -561,7 +565,7 @@ class RestParamDefaults {
 
 		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
-			return req.getPathMatch().get(name, type);
+			return req.getPathMatch().get(partParser, schema, name, type);
 		}
 		
 		private static final ObjectMap getMetaData(Path a, PathObject existing) {
@@ -573,14 +577,17 @@ class RestParamDefaults {
 	}
 
 	static final class BodyObject extends RestMethodParam {
+		private final HttpPartSchema schema;
 		
 		protected BodyObject(Method method, Body a, Type type, RestMethodParam existing) {
 			super(BODY, method, null, type, getMetaData(a, castOrNull(existing, BodyObject.class)));
+			this.schema = getSchema(metaData, method, "@Body");
 		}
 
 		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
-			return req.getBody().asType(type);
+			Object o = req.getBody().schema(schema).asType(type);
+			return o;
 		}
 		
 		private static final ObjectMap getMetaData(Body a, BodyObject existing) {
@@ -591,10 +598,12 @@ class RestParamDefaults {
 	
 	static final class HeaderObject extends RestMethodParam {
 		private final HttpPartParser partParser;
+		private final HttpPartSchema schema;
 
 		protected HeaderObject(Method method, Header a, Type type, PropertyStore ps, RestMethodParam existing) {
 			super(HEADER, method, firstNonEmpty(existing == null ? null : existing.name, a.name(), a.value()), type, getMetaData(a, castOrNull(existing, HeaderObject.class)));
 			this.partParser = a.parser() == HttpPartParser.Null.class ? null : ClassUtils.newInstance(HttpPartParser.class, a.parser(), true, ps);
+			this.schema = getSchema(metaData, method, "@Header");
 		}
 
 		@Override /* RestMethodParam */
@@ -605,7 +614,7 @@ class RestParamDefaults {
 
 		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
-			return req.getHeaders().get(partParser, name, type);
+			return req.getHeaders().get(partParser, schema, name, type);
 		}
 		
 		private static ObjectMap getMetaData(Header a, HeaderObject existing) {
@@ -616,10 +625,12 @@ class RestParamDefaults {
 
 	static final class ResponseHeaderObject extends RestMethodParam {
 		final HttpPartSerializer partSerializer;
+		final HttpPartSchema schema;
 
 		protected ResponseHeaderObject(Method method, ResponseHeader a, Type type, PropertyStore ps, RestMethodParam existing) {
 			super(RESPONSE_HEADER, method, firstNonEmpty(existing == null ? null : existing.name, a.name(), a.value()), type, getMetaData(a, castOrNull(existing, ResponseHeaderObject.class)));
 			this.partSerializer = a.serializer() == HttpPartSerializer.Null.class ? null : ClassUtils.newInstance(HttpPartSerializer.class, a.serializer(), true, ps);
+			this.schema = getSchema(metaData, method, "@Reponse");
 		}
 
 		@Override /* RestMethodParam */
@@ -639,7 +650,7 @@ class RestParamDefaults {
 			v.listener(new ValueListener() {
 				@Override
 				public void onSet(Object newValue) {
-					res.setHeader(name, partSerializer.serialize(HttpPartType.HEADER, newValue));
+					res.setHeader(name, partSerializer.serialize(HttpPartType.HEADER, schema, newValue));
 				}
 			});
 			String def = getMetaData().getString("default");
@@ -777,11 +788,13 @@ class RestParamDefaults {
 	static final class FormDataObject extends RestMethodParam {
 		private final boolean multiPart;
 		private final HttpPartParser partParser;
+		private final HttpPartSchema schema;
 
 		protected FormDataObject(Method method, FormData a, Type type, PropertyStore ps, RestMethodParam existing) {
 			super(FORM_DATA, method, firstNonEmpty(existing == null ? null : existing.name, a.name(), a.value()), type, getMetaData(a, castOrNull(existing, FormDataObject.class)));
-			this.multiPart = a.multipart();
 			this.partParser = a.parser() == HttpPartParser.Null.class ? null : ClassUtils.newInstance(HttpPartParser.class, a.parser(), true, ps);
+			this.schema = getSchema(metaData, method, "@FormData");
+			this.multiPart = schema.getCollectionFormat() == HttpPartSchema.CollectionFormat.MULTI;
 		}
 		
 		@Override /* RestMethodParam */
@@ -795,8 +808,8 @@ class RestParamDefaults {
 		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			if (multiPart)
-				return req.getFormData().getAll(partParser, name, type);
-			return req.getFormData().get(partParser, name, type);
+				return req.getFormData().getAll(partParser, schema, name, type);
+			return req.getFormData().get(partParser, schema, name, type);
 		}
 		
 		private static final ObjectMap getMetaData(FormData a, FormDataObject existing) {
@@ -808,11 +821,13 @@ class RestParamDefaults {
 	static final class QueryObject extends RestMethodParam {
 		private final boolean multiPart;
 		private final HttpPartParser partParser;
+		private final HttpPartSchema schema;
 
 		protected QueryObject(Method method, Query a, Type type, PropertyStore ps, RestMethodParam existing) {
 			super(QUERY, method, firstNonEmpty(existing == null ? null : existing.name, a.name(), a.value()), type, getMetaData(a, castOrNull(existing, QueryObject.class)));
-			this.multiPart = a.multipart();
+			this.multiPart = "multi".equals(a.collectionFormat());
 			this.partParser = a.parser() == HttpPartParser.Null.class ? null : ClassUtils.newInstance(HttpPartParser.class, a.parser(), true, ps);
+			this.schema = getSchema(metaData, method, "@Query");
 		}
 
 		@Override /* RestMethodParam */
@@ -826,8 +841,8 @@ class RestParamDefaults {
 		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			if (multiPart)
-				return req.getQuery().getAll(partParser, name, type);
-			return req.getQuery().get(partParser, name, type);
+				return req.getQuery().getAll(partParser, schema, name, type);
+			return req.getQuery().get(partParser, schema, name, type);
 		}
 		
 		private static final ObjectMap getMetaData(Query a, QueryObject existing) {
@@ -842,7 +857,7 @@ class RestParamDefaults {
 			super(FORM_DATA, method, firstNonEmpty(a.name(), a.value()), type);
 			if (type != Boolean.class && type != boolean.class)
 				throw new RestServletException("Use of @HasForm annotation on parameter that is not a boolean on method ''{0}''", method);
-	}
+		}
 
 		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
@@ -1189,4 +1204,91 @@ class RestParamDefaults {
 	static final boolean isCollection(Type t) {
 		return BeanContext.DEFAULT.getClassMeta(t).isCollectionOrArray();
 	}
+
+	static HttpPartSchema getSchema(ObjectMap md, Method m, String argType) throws InternalServerError {
+		try {
+			return getSchemaBuilder(md).build();
+		} catch (Exception e) {
+			throw new InternalServerError(e, "Invalid {0} argument on class ''{1}'' method ''{2}''", argType, m.getDeclaringClass().getName(), m.getName());
+		}
+	}
+	
+	static HttpPartSchema.Builder getSchemaBuilder(ObjectMap md) throws ParseException {
+		ObjectMap md2 = md.getObjectMap("schema", ObjectMap.EMPTY_MAP);
+		HttpPartSchema.Builder b = HttpPartSchema
+			.create()
+			._default(md.getString("default"))
+			._default(md2.getString("default"))
+			._enum(toSet(md.getString("enum")))
+			._enum(toSet(md2.getString("enum")))
+			.allowEmptyValue(md.getBoolean("allowEmptyValue"))
+			.allowEmptyValue(md2.getBoolean("allowEmptyValue"))
+			.exclusiveMaximum(md.getBoolean("exclusiveMaximum"))
+			.exclusiveMaximum(md2.getBoolean("exclusiveMaximum"))
+			.exclusiveMinimum(md.getBoolean("exclusiveMinimum"))
+			.exclusiveMinimum(md2.getBoolean("exclusiveMinimum"))
+			.required(md.getBoolean("required"))
+			.required(md2.getBoolean("required"))
+			.uniqueItems(md.getBoolean("uniqueItems"))
+			.uniqueItems(md2.getBoolean("uniqueItems"))
+			.collectionFormat(md.getString("collectionFormat"))
+			.collectionFormat(md2.getString("collectionFormat"))
+			.type(md.getString("type"))
+			.type(md2.getString("type"))
+			.format(md.getString("format"))
+			.format(md2.getString("format"))
+			.pattern(md.getString("pattern"))
+			.pattern(md2.getString("pattern"))
+			.maximum(md.get("maximum", Number.class))
+			.maximum(md2.get("maximum", Number.class))
+			.minimum(md.get("minimum", Number.class))
+			.minimum(md2.get("minimum", Number.class))
+			.multipleOf(md.get("multipleOf", Number.class))
+			.multipleOf(md2.get("multipleOf", Number.class))
+			.maxItems(md.get("maxItems", Integer.class))
+			.maxItems(md2.get("maxItems", Integer.class))
+			.maxLength(md.get("maxLength", Integer.class))
+			.maxLength(md2.get("maxLength", Integer.class))
+			.maxProperties(md.get("maxProperties", Integer.class))
+			.maxProperties(md2.get("maxProperties", Integer.class))
+			.minItems(md.get("minItems", Integer.class))
+			.minItems(md2.get("minItems", Integer.class))
+			.minLength(md.get("minLength", Integer.class))
+			.minLength(md2.get("minLength", Integer.class))
+			.minProperties(md.get("minProperties", Integer.class))
+			.minProperties(md2.get("minProperties", Integer.class))
+		;
+		
+		ObjectMap items = md.getObjectMap("items");
+		if (items != null)
+			b.items(getSchemaBuilder(items));
+		
+		ObjectMap additionalProperties = md.getObjectMap("additionalProperties");
+		if (additionalProperties != null)
+			b.additionalProperties(getSchemaBuilder(additionalProperties));
+		
+		ObjectMap properties = md.getObjectMap("properties");
+		if (properties != null) {
+			for (String name : properties.keySet()) {
+				b.property(name, getSchemaBuilder(md.getObjectMap(name)));
+			}
+		}
+		
+		return b;
+	}
+	
+	private static Set<String> toSet(String s) {
+		if (isEmpty(s))
+			return null;
+		Set<String> set = new ASet<>();
+		try {
+			for (Object o : StringUtils.parseListOrCdl(s))
+				set.add(o.toString());
+		} catch (ParseException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return set;
+	}
+	
 }
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 ea1c224..de45749 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
@@ -1078,6 +1078,15 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	 * 
 	 * @return The part serializer associated with this request.
 	 */
+	public HttpPartParser getPartParser() {
+		return restJavaMethod.partParser;
+	}
+
+	/**
+	 * Returns the part serializer associated with this request.
+	 * 
+	 * @return The part serializer associated with this request.
+	 */
 	public HttpPartSerializer getPartSerializer() {
 		return restJavaMethod.partSerializer;
 	}
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 e24cafa..8a22486 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, passThroughHeaders, context.getBeanContext().getClassMeta(ObjectMap.class));
+				ObjectMap m = p.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/annotation/Body.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Body.java
index 9e33dab..2321d3a 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Body.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Body.java
@@ -23,6 +23,7 @@ import java.util.logging.*;
 import org.apache.juneau.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.jsonschema.*;
+import org.apache.juneau.rest.exception.*;
 
 /**
  * REST request body annotation.
@@ -212,8 +213,11 @@ public @interface Body {
 	 * <mk>required</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
 	 * <p>
-	 * Determines whether the body is mandatory. The default value is <jk>false</jk>.
+	 * Determines whether the body is mandatory.
 	 *  
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
 	 * <h5 class='section'>Examples:</h5>
 	 * <p class='bcode'>
 	 * 	<jc>// Used on parameter</jc>
@@ -240,7 +244,7 @@ public @interface Body {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String required() default "";
+	boolean required() default false;
 	
 	//=================================================================================================================
 	// Attributes specific to in=body
@@ -259,7 +263,7 @@ public @interface Body {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
@@ -280,10 +284,10 @@ public @interface Body {
 	//=================================================================================================================
 
 	/**
-	 * TODO
+	 * A serialized example of the body of a request.
 	 * 
 	 * <p>
-	 * This is the JSON or String representation of an example of the body.
+	 * This is the {@link JsonSerializer#DEFAULT_LAX Simple-JSON} or String representation of an example of the body.
 	 * 
 	 * <p>
 	 * This value is converted to a POJO and then serialized to all the registered serializers on the REST method to produce examples for all
@@ -367,7 +371,7 @@ public @interface Body {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is any JSON if the object can be converted to a POJO using {@link JsonParser#DEFAULT} or a simple String if the object
+	 * 		The format is any {@link JsonSerializer#DEFAULT_LAX Simple-JSON} if the object can be converted to a POJO using {@link JsonParser#DEFAULT} or a simple String if the object
 	 * 		can be converted from a String.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
@@ -378,10 +382,10 @@ public @interface Body {
 	String[] example() default {};
 	
 	/**
-	 * TODO
+	 * Serialized examples of the body of a request.
 	 * 
 	 * <p>
-	 * This is a JSON object whose keys are media types and values are string representations of that value.
+	 * This is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object whose keys are media types and values are string representations of that value.
 	 * 
 	 * <p>
 	 * In general you won't need to populate this value directly since it will automatically be calculated based on the value provided in the {@link #example()} field.
@@ -399,7 +403,7 @@ public @interface Body {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a Simplified JSON object with string keys (media type) and string values (example for that media type) .
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object with string keys (media type) and string values (example for that media type) .
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 	<li>
@@ -418,7 +422,7 @@ public @interface Body {
 	 * Free-form value for the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
 	 * <p>
-	 * This is a JSON object that makes up the swagger information for this parameter-info.
+	 * This is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object that makes up the swagger information for this parameter-info.
 	 * 
 	 * <p>
 	 * The following are completely equivalent ways of defining the swagger description of the body:
@@ -466,7 +470,9 @@ public @interface Body {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a Simplified JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
+	 * 	<li>
+	 * 		Automatic validation is NOT performed on input based on attributes in this value.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 		<br>The following two example are considered equivalent:
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Contact.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Contact.java
index af9cfc4..3f9458b 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Contact.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Contact.java
@@ -17,6 +17,8 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
 
+import org.apache.juneau.json.*;
+
 /**
  * Swagger contact annotation.
  * 
@@ -166,7 +168,7 @@ public @interface Contact {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a Simplified JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 		<br>The following two example are considered equivalent:
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ExternalDocs.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ExternalDocs.java
index e213bd3..0b45080 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ExternalDocs.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ExternalDocs.java
@@ -12,6 +12,8 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.rest.annotation;
 
+import org.apache.juneau.json.*;
+
 /**
  * TODO
  * 
@@ -64,7 +66,7 @@ public @interface ExternalDocs {
 	 * Free-form value for the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#externalDocumentationObject">ExternalDocumentation</a> object.
 	 * 
 	 * <p>
-	 * This is a JSON object that makes up the swagger information for this field.
+	 * This is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object that makes up the swagger information for this field.
 	 * 
 	 * <p>
 	 * The following are completely equivalent ways of defining the swagger description of documentation:
@@ -113,7 +115,7 @@ public @interface ExternalDocs {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a Simplified JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 		<br>The following two example are considered equivalent:
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/FormData.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/FormData.java
index 1c42387..657a15f 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/FormData.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/FormData.java
@@ -16,9 +16,14 @@ import static java.lang.annotation.ElementType.*;
 import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
+import java.util.*;
 
+import org.apache.juneau.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.oapi.*;
+import org.apache.juneau.json.*;
 import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.exception.*;
 
 /**
  * Annotation that can be applied to a parameter of a {@link RestMethod @RestMethod} annotated method to identify it as a form post
@@ -68,24 +73,10 @@ import org.apache.juneau.rest.*;
 public @interface FormData {
 
 	/**
-	 * Specify <jk>true</jk> if using multi-part parameters to represent collections and arrays.
-	 * 
-	 * <p>
-	 * Normally, we expect single parameters to be specified in UON notation for representing collections of values
-	 * (e.g. <js>"key=(1,2,3)"</js>.
-	 * This annotation allows the use of multi-part parameters to represent collections (e.g.
-	 * <js>"key=1&amp;key=2&amp;key=3"</js>.
-	 * 
-	 * <p>
-	 * This setting should only be applied to Java parameters of type array or Collection.
-	 */
-	boolean multipart() default false;
-
-	/**
 	 * Specifies the {@link HttpPartParser} class used for parsing values from strings.
 	 * 
 	 * <p>
-	 * The default value for this parser is inherited from the servlet/method which defaults to {@link UonPartParser}.
+	 * The default value for this parser is inherited from the servlet/method which defaults to {@link OapiPartParser}.
 	 * <br>You can use {@link SimplePartParser} to parse POJOs that are directly convertible from <code>Strings</code>.
 	 */
 	Class<? extends HttpPartParser> parser() default HttpPartParser.Null.class;
@@ -147,18 +138,12 @@ public @interface FormData {
 	 * <mk>required</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
 	 * <p>
-	 * Determines whether this parameter is mandatory. The default value is <jk>false</jk>.
-	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is boolean.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * Determines whether the parameter is mandatory.
+	 *  
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
 	 */
-	String required() default "";
+	boolean required() default false;
 	
 	//=================================================================================================================
 	// Attributes specific to parameters other than body
@@ -170,29 +155,41 @@ public @interface FormData {
 	 * <p>
 	 * The type of the parameter. 
 	 * 
-	 * <p>
-	 * Note that per the Swagger specification, this value is required and must be a simple type (e.g. <js>"string"</js>, <js>"number"</js>...).
-	 * <br>However, Juneau allows for arbitrarily-complex POJOs such as beans in form parameters using UON notation, this attribute can be left off in lieu of a {@link #schema()} 
-	 * attribute.
-	 * 
 	 * <p> 
 	 * The possible values are:
-	 * <ul>
-	 * 	<li><js>"string"</js>
-	 * 	<li><js>"number"</js>
-	 * 	<li><js>"integer"</js>
-	 * 	<li><js>"boolean"</js>
-	 * 	<li><js>"array"</js>
-	 * 	<li><js>"file"</js>
-	 * </ul>
-	 * 
-	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
+	 * 		<js>"string"</js>
+	 * 		<br>Parameter must be a string or a POJO convertible from a string.
+	 * 	<li>
+	 * 		<js>"number"</js>
+	 * 		<br>Parameter must be a number primitive or number object.
+	 * 		<br>If parameter is <code>Object</code>, creates either a <code>Float</code> or <code>Double</code> depending on the size of the number.
+	 * 	<li>
+	 * 		<js>"integer"</js>
+	 * 		<br>Parameter must be a integer/long primitive or integer/long object.
+	 * 		<br>If parameter is <code>Object</code>, creates either a <code>Short</code>, <code>Integer</code>, or <code>Long</code> depending on the size of the number.
+	 * 	<li>
+	 * 		<js>"boolean"</js>
+	 * 		<br>Parameter must be a boolean primitive or object.
+	 * 	<li>
+	 * 		<js>"array"</js>
+	 * 		<br>Parameter must be an array or collection.
+	 * 		<br>Elements must be strings or POJOs convertible from strings.
+	 * 		<br>If parameter is <code>Object</code>, creates an {@link ObjectList}.
+	 * 	<li>
+	 * 		<js>"object"</js>
+	 * 		<br>Parameter must be a map or bean.
+	 * 		<br>If parameter is <code>Object</code>, creates an {@link ObjectMap}.
+	 * 		<br>Note that this is an extension of the OpenAPI schema as Juneau allows for arbitrarily-complex POJOs to be serialized as HTTP parts.
+	 * 	<li>
+	 * 		<js>"file"</js>
+	 * 		<br>This type is currently not supported.
 	 * </ul>
 	 * 
+	 * <p>
+	 * If the type is not specified, it will be auto-detected based on the parameter class type.
+	 * 
 	 * <h5 class='section'>See Also:</h5>
 	 * <ul class='doctree'>
 	 * 	<li class='link'><a class='doclink' href='https://swagger.io/specification/#dataTypes'>Swagger specification &gt; Data Types</a>
@@ -205,15 +202,48 @@ public @interface FormData {
 	 * 
 	 * <p>
 	 * The extending format for the previously mentioned <a href='https://swagger.io/specification/v2/#parameterType'>type</a>. 
-	 * See <a href='https://swagger.io/specification/v2/#dataTypeFormat'>Data Type Formats</a> for further details.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
+	 * <p> 
+	 * The possible values are:
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is plain-text.
+	 * 		<js>"int32"</js> - Signed 32 bits.
+	 * 		<br>Only valid with type <js>"integer"</js>.
 	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
+	 * 		<js>"int64"</js> - Signed 64 bits.
+	 * 		<br>Only valid with type <js>"integer"</js>.
+	 * 	<li>
+	 * 		<js>"float"</js> - 32-bit floating point number.
+	 * 		<br>Only valid with type <js>"number"</js>.
+	 * 	<li>
+	 * 		<js>"double"</js> - 64-bit floating point number.
+	 * 		<br>Only valid with type <js>"number"</js>.
+	 * 	<li>
+	 * 		<js>"byte"</js> - BASE-64 encoded characters.
+	 * 		<br>Only valid with type <js>"string"</js>.
+	 * 		<br>Parameters of type POJO convertible from string are converted after the string has been decoded.
+	 * 	<li>
+	 * 		<js>"binary"</js> - Hexadecimal encoded octets (e.g. <js>"00FF"</js>).
+	 * 		<br>Only valid with type <js>"string"</js>.
+	 * 		<br>Parameters of type POJO convertible from string are converted after the string has been decoded.
+	 * 	<li>
+	 * 		<js>"date"</js> - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 full-date</a>.
+	 * 		<br>Only valid with type <js>"string"</js>.
+	 * 	<li>
+	 * 		<js>"date-time"</js> - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 date-time</a>.
+	 * 		<br>Only valid with type <js>"string"</js>.
+	 * 	<li>
+	 * 		<js>"password"</js> - Used to hint UIs the input needs to be obscured.
+	 * 		<br>This format does not affect the serialization or parsing of the parameter.
+	 * 	<li>
+	 * 		<js>"uon"</js> - UON notation (e.g. <js>"(foo=bar,baz=@(qux,123))"</js>). 
+	 * 		<br>Only valid with type <js>"object"</js>.
+	 * 		<br>If not specified, then the input is interpreted as plain-text and is converted to a POJO directly.
+	 * </ul>
+	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul class='doctree'>
+	 * 	<li class='link'><a class='doclink' href='https://swagger.io/specification/v2/#dataTypeFormat'>Swagger specification &gt; Data Type Formats</a>
 	 * </ul>
 	 */
 	String format() default "";
@@ -224,271 +254,279 @@ public @interface FormData {
 	 * <p>
 	 * Sets the ability to pass empty-valued parameters. 
 	 * <br>This is valid only for either query or formData parameters and allows you to send a parameter with a name only or an empty value. 
-	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is boolean.
-	 * 	<li>
-	 * 		Default value is <jk>false</jk>.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <br>The default value is <jk>false</jk>.
 	 */
-	String allowEmptyValue() default "";
+	boolean allowEmptyValue() default false;
 
 	/**
-	 * <mk>pattern</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>items</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a regular expression according to the ECMA 262 regular expression dialect.
-	 * 	<li>
-	 * 		This string SHOULD be a valid regular expression.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Describes the type of items in the array.
+	 * <p>
+	 * Required if <code>type</code> is <js>"array"</js>. 
+	 * <br>Can only be used if <code>type</code> is <js>"array"</js>.
 	 */
-	String pattern() default "";
+	Items items() default @Items;	
 
 	/**
 	 * <mk>collectionFormat</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
 	 * <p>
-	 * Determines the format of the array if type array is used. 
-	 * <br>Possible values are:
-	 * <ul>
-	 * 	<li><js>"csv"</js> (default) - Comma-separated values (e.g. <js>"foo,bar"</js>).
-	 * 	<li><js>"ssv"</js> - Space-separated values (e.g. <js>"foo bar"</js>).
-	 * 	<li><js>"tsv"</js> - Tab-separated values (e.g. <js>"foo\tbar"</js>).
-	 * 	<li><js>"pipes</js> - Pipe-separated values (e.g. <js>"foo|bar"</js>).
-	 * 	<li><js>"multi"</js> - Corresponds to multiple parameter instances instead of multiple values for a single instance (e.g. <js>"foo=bar&amp;foo=baz"</js>). 
-	 * </ul>
+	 * Determines the format of the array if <code>type</code> <js>"array"</js> is used. 
+	 * <br>Can only be used if <code>type</code> is <js>"array"</js>.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
+	 * <br>Possible values are:
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
+	 * 		<js>"csv"</js> (default) - Comma-separated values (e.g. <js>"foo,bar"</js>).
+	 * 	<li>
+	 * 		<js>"ssv"</js> - Space-separated values (e.g. <js>"foo bar"</js>).
+	 * 	<li>
+	 * 		<js>"tsv"</js> - Tab-separated values (e.g. <js>"foo\tbar"</js>).
+	 * 	<li>
+	 * 		<js>"pipes</js> - Pipe-separated values (e.g. <js>"foo|bar"</js>).
+	 * 	<li>
+	 * 		<js>"multi"</js> - Corresponds to multiple parameter instances instead of multiple values for a single instance (e.g. <js>"foo=bar&amp;foo=baz"</js>). 
+	 * 	<li>
+	 * 		<js>"uon"</js> - UON notation (e.g. <js>"@(foo,bar)"</js>). 
 	 * </ul>
+	 * 
+	 * <p>
+	 * Note that for collections/arrays parameters with POJO element types, the input is broken into a string array before being converted into POJO elements. 
 	 */
 	String collectionFormat() default "";
 
 	/**
+	 * <mk>default</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * 
+	 * <p>
+	 * Declares the value of the parameter that the server will use if none is provided, for example a "count" to control the number of results per page might default to 100 if not supplied by the client in the request. 
+	 * <br>(Note: "default" has no meaning for required parameters.) 
+	 * 
+	 * <p>
+	 * Additionally, this value is used to create instances of POJOs that are then serialized as language-specific examples in the generated Swagger documentation
+	 * if the examples are not defined in some other way.
+	 * 
+	 * <p>
+	 * The format of this value is a string.
+	 * <br>Multiple lines are concatenated with newlines.
+	 * 
+	 * <h5 class='section'>Examples:</h5>
+	 * <p class='bcode w800'>
+	 * 	<jk>public</jk> Order placeOrder(
+	 * 		<jk>@FormData</jk>(name=<js>"petId"</jk>, _default=<js>"100"</js>) <jk>long</jk> petId,
+	 * 		<jk>@FormData</jk>(name=<js>"additionalInfo"</jk>, format=<js>"uon"</js>, _default=<js>"(rushOrder=false)"</js>) AdditionalInfo additionalInfo,
+	 * 		<jk>@FormData</jk>(name=<js>"flags"</jk>, collectionFormat=<js>"uon"</js>, _default=<js>"@(new-customer)"</js>) String[] flags
+	 * 	) {...}
+	 * </p>
+	 */
+	String[] _default() default {};
+	
+	/**
 	 * <mk>maximum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON number.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Defines the maximum value for a parameter of numeric types.
+	 * <br>The value must be a valid JSON number.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
 	 */
 	String maximum() default "";
 	
 	/**
+	 * <mk>exclusiveMaximum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * 
+	 * <p>
+	 * Defines whether the maximum is matched exclusively.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
+	 * <br>If <jk>true</jk>, must be accompanied with <code>maximum</code>.
+	 */
+	boolean exclusiveMaximum() default false;
+
+	/**
 	 * <mk>minimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON number.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Defines the minimum value for a parameter of numeric types.
+	 * <br>The value must be a valid JSON number.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
 	 */
 	String minimum() default "";
 
 	/**
-	 * <mk>multipleOf</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>exclusiveMinimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Defines whether the minimum is matched exclusively.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
+	 * <br>If <jk>true</jk>, must be accompanied with <code>minimum</code>.
 	 */
-	String multipleOf() default "";
+	boolean exclusiveMinimum() default false;
 	
 	/**
 	 * <mk>maxLength</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * A string instance is valid against this keyword if its length is less than, or equal to, the value of this keyword.
+	 * <br>The length of a string instance is defined as the number of its characters as defined by <a href='https://tools.ietf.org/html/rfc4627'>RFC 4627</a>.
+	 * <br>The value <code>-1</code> is always ignored.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"string"</js>.
 	 */
-	String maxLength() default "";
+	long maxLength() default -1;
 	
 	/**
 	 * <mk>minLength</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * A string instance is valid against this keyword if its length is greater than, or equal to, the value of this keyword.
+	 * <br>The length of a string instance is defined as the number of its characters as defined by <a href='https://tools.ietf.org/html/rfc4627'>RFC 4627</a>.
+	 * <br>The value <code>-1</code> is always ignored.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"string"</js>.
 	 */
-	String minLength() default "";
+	long minLength() default -1;
 	
 	/**
-	 * <mk>maxItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>pattern</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
-	 */
-	String maxItems() default "";
-
-	/**
-	 * <mk>minItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <p>
+	 * A string input is valid if it matches the specified regular expression pattern.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"string"</js>.
 	 */
-	String minItems() default "";
+	String pattern() default "";
 
 	/**
-	 * <mk>exclusiveMaximum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>maxItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * An array or collection is valid if its size is less than, or equal to, the value of this keyword.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"array"</js>.
 	 */
-	String exclusiveMaximum() default "";
+	long maxItems() default -1;
 
 	/**
-	 * <mk>exclusiveMinimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>minItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
-	 */
-	String exclusiveMinimum() default "";
-	
-	/**
-	 * <mk>uniqueItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <p>
+	 * An array or collection is valid if its size is greater than, or equal to, the value of this keyword.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is boolean.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
-	 */
-	String uniqueItems() default "";
-	
-	/**
-	 * <mk>schema</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON object.
-	 * 		<br>Multiple lines are concatenated with newlines.
-	 * 	<li>
-	 * 		The leading/trailing <code>{ }</code> characters are optional.
-	 * 		<br>The following two example are considered equivalent:
-	 * 		<ul>
-	 * 			<li><code>schema=<js>"{type:'string',format:'binary'}"</js></code>
-	 * 			<li><code>schema=<js>"type:'string',format:'binary'"</js></code>
-	 * 		<ul>
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Only allowed for the following types: <js>"array"</js>.
 	 */
-	Schema schema() default @Schema;
-	
+	long minItems() default -1;
+
 	/**
-	 * <mk>default</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>uniqueItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
 	 * <p>
-	 * Additionally, this method can be used to define a default value for a missing form data entry.
+	 * If <jk>true</jk>, the input validates successfully if all of its elements are unique.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is any JSON.
-	 * 		<br>Multiple lines are concatenated with newlines.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * <br>If the parameter type is a subclass of {@link Set}, this validation is skipped (since a set can only contain unique items anyway).
+	 * <br>Otherwise, the collection or array is checked for duplicate items.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"array"</js>.
 	 */
-	String[] _default() default {};
+	boolean uniqueItems() default false;
 	
 	/**
 	 * <mk>enum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON array or comma-delimited list.
-	 * 		<br>Multiple lines are concatenated with newlines.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * If specified, the input validates successfully if it is equal to one of the elements in this array.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} array or comma-delimited list.
+	 * <br>Multiple lines are concatenated with newlines.
+	 * 
+	 * <h5 class='section'>Examples:</h5>
+	 * <p class='bcode w800'>
+	 * 	<jk>public</jk> Collection&lt;Pet&gt; findPetsByStatus(
+	 * 		<ja>@FormData</ja>(
+	 * 			name=<js>"status"</js>, 
+	 * 			_enum=<js>"AVAILABLE,PENDING,SOLD"</js>,
+	 * 		) PetStatus status
+	 * 	) {...}
+	 * </p>
+	 * <p class='bcode w800'>
+	 * 	<jk>public</jk> Collection&lt;Pet&gt; findPetsByStatus(
+	 * 		<ja>@FormData</ja>(
+	 * 			name=<js>"status"</js>, 
+	 * 			_enum=<js>"['AVAILABLE','PENDING','SOLD']"</js>,
+	 * 		) PetStatus status
+	 * 	) {...}
+	 * </p>
 	 */
 	String[] _enum() default {};
 	
 	/**
-	 * <mk>items</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>multipleOf</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON object.
-	 * 		<br>Multiple lines are concatenated with newlines.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * A numeric instance is valid if the result of the division of the instance by this keyword's value is an integer.
+	 * <br>The value must be a valid JSON number.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
 	 */
-	Items items() default @Items;	
+	String multipleOf() default "";
+	
+	//=================================================================================================================
+	// Other
+	//=================================================================================================================
 	
 	/**
-	 * TODO
+	 * A serialized example of the parameter.
 	 * 
 	 * <p>
 	 * This attribute defines a JSON representation of the value that is used by {@link BasicRestInfoProvider} to construct
@@ -497,7 +535,7 @@ public @interface FormData {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object or plain text string.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object or plain text string.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -556,7 +594,9 @@ public @interface FormData {
 	 * 	<li>
 	 * 		Note that the only swagger field you can't specify using this value is <js>"name"</js> whose value needs to be known during servlet initialization.
 	 * 	<li>
-	 * 		The format is a Simplified JSON object.
+	 * 		Automatic validation is NOT performed on input based on attributes in this value.
+	 * 	<li>
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 		<br>The following two example are considered equivalent:
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Header.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Header.java
index a7f9ba0..dcae57e 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Header.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Header.java
@@ -16,9 +16,14 @@ import static java.lang.annotation.ElementType.*;
 import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
+import java.util.*;
 
+import org.apache.juneau.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.oapi.*;
+import org.apache.juneau.json.*;
 import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.exception.*;
 
 /**
  * Annotation that can be applied to a parameter of a {@link RestMethod @RestMethod} annotated method to identify it as a HTTP
@@ -58,7 +63,7 @@ public @interface Header {
 	 * Specifies the {@link HttpPartParser} class used for parsing values from strings.
 	 * 
 	 * <p>
-	 * The default value for this parser is inherited from the servlet/method which defaults to {@link UonPartParser}.
+	 * The default value for this parser is inherited from the servlet/method which defaults to {@link OapiPartParser}.
 	 * <br>You can use {@link SimplePartParser} to parse POJOs that are directly convertible from <code>Strings</code>.
 	 */
 	Class<? extends HttpPartParser> parser() default HttpPartParser.Null.class;
@@ -112,18 +117,12 @@ public @interface Header {
 	 * <mk>required</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
 	 * <p>
-	 * Determines whether this parameter is mandatory. The default value is <jk>false</jk>.
-	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is boolean.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * Determines whether the parameter is mandatory.
+	 *  
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
 	 */
-	String required() default "";
+	boolean required() default false;
 	
 	//=================================================================================================================
 	// Attributes specific to parameters other than body
@@ -135,27 +134,41 @@ public @interface Header {
 	 * <p>
 	 * The type of the parameter. 
 	 * 
-	 * <p>
-	 * Note that per the Swagger specification, this value is required and must be a simple type (e.g. <js>"string"</js>, <js>"number"</js>...).
-	 * <br>However, Juneau allows for arbitrarily-complex POJOs such as beans in form parameters using UON notation, this attribute can be left off in lieu of a {@link #schema()} 
-	 * attribute.
-	 * 
 	 * <p> 
 	 * The possible values are:
-	 * <ul>
-	 * 	<li><js>"string"</js>
-	 * 	<li><js>"number"</js>
-	 * 	<li><js>"integer"</js>
-	 * 	<li><js>"boolean"</js>
-	 * 	<li><js>"array"</js>
-	 * 	<li><js>"file"</js>
-	 * </ul>
-	 * 
-	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
+	 * 		<js>"string"</js>
+	 * 		<br>Parameter must be a string or a POJO convertible from a string.
+	 * 	<li>
+	 * 		<js>"number"</js>
+	 * 		<br>Parameter must be a number primitive or number object.
+	 * 		<br>If parameter is <code>Object</code>, creates either a <code>Float</code> or <code>Double</code> depending on the size of the number.
+	 * 	<li>
+	 * 		<js>"integer"</js>
+	 * 		<br>Parameter must be a integer/long primitive or integer/long object.
+	 * 		<br>If parameter is <code>Object</code>, creates either a <code>Short</code>, <code>Integer</code>, or <code>Long</code> depending on the size of the number.
+	 * 	<li>
+	 * 		<js>"boolean"</js>
+	 * 		<br>Parameter must be a boolean primitive or object.
+	 * 	<li>
+	 * 		<js>"array"</js>
+	 * 		<br>Parameter must be an array or collection.
+	 * 		<br>Elements must be strings or POJOs convertible from strings.
+	 * 		<br>If parameter is <code>Object</code>, creates an {@link ObjectList}.
+	 * 	<li>
+	 * 		<js>"object"</js>
+	 * 		<br>Parameter must be a map or bean.
+	 * 		<br>If parameter is <code>Object</code>, creates an {@link ObjectMap}.
+	 * 		<br>Note that this is an extension of the OpenAPI schema as Juneau allows for arbitrarily-complex POJOs to be serialized as HTTP parts.
+	 * 	<li>
+	 * 		<js>"file"</js>
+	 * 		<br>This type is currently not supported.
+	 * </ul>
+	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul class='doctree'>
+	 * 	<li class='link'><a class='doclink' href='https://swagger.io/specification/#dataTypes'>Swagger specification &gt; Data Types</a>
 	 * </ul>
 	 */
 	String type() default "";
@@ -165,269 +178,322 @@ public @interface Header {
 	 * 
 	 * <p>
 	 * The extending format for the previously mentioned <a href='https://swagger.io/specification/v2/#parameterType'>type</a>. 
-	 * See <a href='https://swagger.io/specification/v2/#dataTypeFormat'>Data Type Formats</a> for further details.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
+	 * <p> 
+	 * The possible values are:
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is plain-text.
+	 * 		<js>"int32"</js> - Signed 32 bits.
+	 * 		<br>Only valid with type <js>"integer"</js>.
 	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
+	 * 		<js>"int64"</js> - Signed 64 bits.
+	 * 		<br>Only valid with type <js>"integer"</js>.
+	 * 	<li>
+	 * 		<js>"float"</js> - 32-bit floating point number.
+	 * 		<br>Only valid with type <js>"number"</js>.
+	 * 	<li>
+	 * 		<js>"double"</js> - 64-bit floating point number.
+	 * 		<br>Only valid with type <js>"number"</js>.
+	 * 	<li>
+	 * 		<js>"byte"</js> - BASE-64 encoded characters.
+	 * 		<br>Only valid with type <js>"string"</js>.
+	 * 		<br>Parameters of type POJO convertible from string are converted after the string has been decoded.
+	 * 	<li>
+	 * 		<js>"binary"</js> - Hexadecimal encoded octets (e.g. <js>"00FF"</js>).
+	 * 		<br>Only valid with type <js>"string"</js>.
+	 * 		<br>Parameters of type POJO convertible from string are converted after the string has been decoded.
+	 * 	<li>
+	 * 		<js>"date"</js> - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 full-date</a>.
+	 * 		<br>Only valid with type <js>"string"</js>.
+	 * 	<li>
+	 * 		<js>"date-time"</js> - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 date-time</a>.
+	 * 		<br>Only valid with type <js>"string"</js>.
+	 * 	<li>
+	 * 		<js>"password"</js> - Used to hint UIs the input needs to be obscured.
+	 * 		<br>This format does not affect the serialization or parsing of the parameter.
+	 * 	<li>
+	 * 		<js>"uon"</js> - UON notation (e.g. <js>"(foo=bar,baz=@(qux,123))"</js>). 
+	 * 		<br>Only valid with type <js>"object"</js>.
+	 * 		<br>If not specified, then the input is interpreted as plain-text and is converted to a POJO directly.
+	 * </ul>
+	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul class='doctree'>
+	 * 	<li class='link'><a class='doclink' href='https://swagger.io/specification/v2/#dataTypeFormat'>Swagger specification &gt; Data Type Formats</a>
 	 * </ul>
 	 */
 	String format() default "";
 	
 	/**
-	 * <mk>pattern</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>items</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a regular expression according to the ECMA 262 regular expression dialect.
-	 * 	<li>
-	 * 		This string SHOULD be a valid regular expression.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Describes the type of items in the array.
+	 * <p>
+	 * Required if <code>type</code> is <js>"array"</js>. 
+	 * <br>Can only be used if <code>type</code> is <js>"array"</js>.
 	 */
-	String pattern() default "";
-
+	Items items() default @Items;	
+	
 	/**
 	 * <mk>collectionFormat</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
 	 * <p>
-	 * Determines the format of the array if type array is used. 
-	 * <br>Possible values are:
-	 * <ul>
-	 * 	<li><js>"csv"</js> (default) - Comma-separated values (e.g. <js>"foo,bar"</js>).
-	 * 	<li><js>"ssv"</js> - Space-separated values (e.g. <js>"foo bar"</js>).
-	 * 	<li><js>"tsv"</js> - Tab-separated values (e.g. <js>"foo\tbar"</js>).
-	 * 	<li><js>"pipes</js> - Pipe-separated values (e.g. <js>"foo|bar"</js>).
-	 * </ul>
+	 * Determines the format of the array if <code>type</code> <js>"array"</js> is used. 
+	 * <br>Can only be used if <code>type</code> is <js>"array"</js>.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
+	 * <br>Possible values are:
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
+	 * 		<js>"csv"</js> (default) - Comma-separated values (e.g. <js>"foo,bar"</js>).
+	 * 	<li>
+	 * 		<js>"ssv"</js> - Space-separated values (e.g. <js>"foo bar"</js>).
+	 * 	<li>
+	 * 		<js>"tsv"</js> - Tab-separated values (e.g. <js>"foo\tbar"</js>).
+	 * 	<li>
+	 * 		<js>"pipes</js> - Pipe-separated values (e.g. <js>"foo|bar"</js>).
+	 * 	<li>
+	 * 		<js>"multi"</js> - Corresponds to multiple parameter instances instead of multiple values for a single instance (e.g. <js>"foo=bar&amp;foo=baz"</js>). 
+	 * 	<li>
+	 * 		<js>"uon"</js> - UON notation (e.g. <js>"@(foo,bar)"</js>). 
+	 * 	<li>
 	 * </ul>
+	 * 
+	 * <p>
+	 * Note that for collections/arrays parameters with POJO element types, the input is broken into a string array before being converted into POJO elements. 
 	 */
 	String collectionFormat() default "";
 
 	/**
+	 * <mk>default</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * 
+	 * <p>
+	 * Declares the value of the parameter that the server will use if none is provided, for example a "count" to control the number of results per page might default to 100 if not supplied by the client in the request. 
+	 * <br>(Note: "default" has no meaning for required parameters.) 
+	 * 
+	 * <p>
+	 * Additionally, this value is used to create instances of POJOs that are then serialized as language-specific examples in the generated Swagger documentation
+	 * if the examples are not defined in some other way.
+	 * 
+	 * <p>
+	 * The format of this value is a string.
+	 * <br>Multiple lines are concatenated with newlines.
+	 * 
+	 * <h5 class='section'>Examples:</h5>
+	 * <p class='bcode w800'>
+	 * 	<jk>public</jk> Order placeOrder(
+	 * 		<jk>@Header</jk>(name=<js>"X-PetId"</jk>, _default=<js>"100"</js>) <jk>long</jk> petId,
+	 * 		<jk>@Header</jk>(name=<js>"X-AdditionalInfo"</jk>, format=<js>"uon"</js>, _default=<js>"(rushOrder=false)"</js>) AdditionalInfo additionalInfo,
+	 * 		<jk>@Header</jk>(name=<js>"X-Flags"</jk>, collectionFormat=<js>"uon"</js>, _default=<js>"@(new-customer)"</js>) String[] flags
+	 * 	) {...}
+	 * </p>
+	 */
+	String[] _default() default {};
+	
+	/**
 	 * <mk>maximum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON number.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Defines the maximum value for a parameter of numeric types.
+	 * <br>The value must be a valid JSON number.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
 	 */
 	String maximum() default "";
 	
 	/**
+	 * <mk>exclusiveMaximum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * 
+	 * <p>
+	 * Defines whether the maximum is matched exclusively.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
+	 * <br>If <jk>true</jk>, must be accompanied with <code>maximum</code>.
+	 */
+	boolean exclusiveMaximum() default false;
+
+	/**
 	 * <mk>minimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON number.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Defines the minimum value for a parameter of numeric types.
+	 * <br>The value must be a valid JSON number.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
 	 */
 	String minimum() default "";
-
+	
 	/**
-	 * <mk>multipleOf</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>exclusiveMinimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Defines whether the minimum is matched exclusively.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
+	 * <br>If <jk>true</jk>, must be accompanied with <code>minimum</code>.
 	 */
-	String multipleOf() default "";
+	boolean exclusiveMinimum() default false;
 	
 	/**
 	 * <mk>maxLength</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * A string instance is valid against this keyword if its length is less than, or equal to, the value of this keyword.
+	 * <br>The length of a string instance is defined as the number of its characters as defined by <a href='https://tools.ietf.org/html/rfc4627'>RFC 4627</a>.
+	 * <br>The value <code>-1</code> is always ignored.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"string"</js>.
 	 */
-	String maxLength() default "";
+	long maxLength() default -1;
 	
 	/**
 	 * <mk>minLength</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * A string instance is valid against this keyword if its length is greater than, or equal to, the value of this keyword.
+	 * <br>The length of a string instance is defined as the number of its characters as defined by <a href='https://tools.ietf.org/html/rfc4627'>RFC 4627</a>.
+	 * <br>The value <code>-1</code> is always ignored.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"string"</js>.
 	 */
-	String minLength() default "";
+	long minLength() default -1;
 	
 	/**
-	 * <mk>maxItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>pattern</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
-	 */
-	String maxItems() default "";
-
-	/**
-	 * <mk>minItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <p>
+	 * A string input is valid if it matches the specified regular expression pattern.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"string"</js>.
 	 */
-	String minItems() default "";
+	String pattern() default "";
 
 	/**
-	 * <mk>exclusiveMaximum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>maxItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * An array or collection is valid if its size is less than, or equal to, the value of this keyword.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"array"</js>.
 	 */
-	String exclusiveMaximum() default "";
+	long maxItems() default -1;
 
 	/**
-	 * <mk>exclusiveMinimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>minItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
-	 */
-	String exclusiveMinimum() default "";
-	
-	/**
-	 * <mk>uniqueItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <p>
+	 * An array or collection is valid if its size is greater than, or equal to, the value of this keyword.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is boolean.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
-	 */
-	String uniqueItems() default "";
-	
-	/**
-	 * <mk>schema</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON object.
-	 * 		<br>Multiple lines are concatenated with newlines.
-	 * 	<li>
-	 * 		The leading/trailing <code>{ }</code> characters are optional.
-	 * 		<br>The following two example are considered equivalent:
-	 * 		<ul>
-	 * 			<li><code>schema=<js>"{type:'string',format:'binary'}"</js></code>
-	 * 			<li><code>schema=<js>"type:'string',format:'binary'"</js></code>
-	 * 		<ul>
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Only allowed for the following types: <js>"array"</js>.
 	 */
-	Schema schema() default @Schema;
-	
+	long minItems() default -1;
+
 	/**
-	 * <mk>default</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>uniqueItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
 	 * <p>
-	 * Additionally, this method can be used to define a default value for a missing header entry.
+	 * If <jk>true</jk> the input validates successfully if all of its elements are unique.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is any JSON.
-	 * 		<br>Multiple lines are concatenated with newlines.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * <br>If the parameter type is a subclass of {@link Set}, this validation is skipped (since a set can only contain unique items anyway).
+	 * <br>Otherwise, the collection or array is checked for duplicate items.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"array"</js>.
 	 */
-	String[] _default() default {};
+	boolean uniqueItems() default false;
 	
 	/**
 	 * <mk>enum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON array or comma-delimited list.
-	 * 		<br>Multiple lines are concatenated with newlines.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * If specified, the input validates successfully if it is equal to one of the elements in this array.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} array or comma-delimited list.
+	 * <br>Multiple lines are concatenated with newlines.
+	 * 
+	 * <h5 class='section'>Examples:</h5>
+	 * <p class='bcode w800'>
+	 * 	<jk>public</jk> Collection&lt;Pet&gt; findPetsByStatus(
+	 * 		<ja>@Header</ja>(
+	 * 			name=<js>"X-Status"</js>, 
+	 * 			_enum=<js>"AVAILABLE,PENDING,SOLD"</js>,
+	 * 		) PetStatus status
+	 * 	) {...}
+	 * </p>
+	 * <p class='bcode w800'>
+	 * 	<jk>public</jk> Collection&lt;Pet&gt; findPetsByStatus(
+	 * 		<ja>@Header</ja>(
+	 * 			name=<js>"X-Status"</js>, 
+	 * 			_enum=<js>"['AVAILABLE','PENDING','SOLD']"</js>,
+	 * 		) PetStatus status
+	 * 	) {...}
+	 * </p>
 	 */
 	String[] _enum() default {};
 	
 	/**
-	 * <mk>items</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>multipleOf</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON object.
-	 * 		<br>Multiple lines are concatenated with newlines.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * A numeric instance is valid if the result of the division of the instance by this keyword's value is an integer.
+	 * <br>The value must be a valid JSON number.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
 	 */
-	Items items() default @Items;	
+	String multipleOf() default "";
+
+	//=================================================================================================================
+	// Other
+	//=================================================================================================================
 	
 	/**
-	 * TODO
+	 * A serialized example of the parameter.
 	 * 
 	 * <p>
 	 * This attribute defines a JSON representation of the value that is used by {@link BasicRestInfoProvider} to construct
@@ -436,7 +502,7 @@ public @interface Header {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object or plain text string.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object or plain text string.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -497,7 +563,9 @@ public @interface Header {
 	 * 	<li>
 	 * 		Note that the only swagger field you can't specify using this value is <js>"name"</js> whose value needs to be known during servlet initialization.
 	 * 	<li>
-	 * 		The format is a Simplified JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
+	 * 	<li>
+	 * 		Automatic validation is NOT performed on input based on attributes in this value.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 		<br>The following two example are considered equivalent:
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Items.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Items.java
index 3c881d7..1e46e18 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Items.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Items.java
@@ -17,6 +17,8 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
 
+import org.apache.juneau.json.*;
+
 /**
  * Swagger schema annotation.
  * 
@@ -147,7 +149,7 @@ public @interface Items {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String maxLength() default "";
+	long maxLength() default -1;
 	
 	/**
 	 * <mk>minLength</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#itemsObject">Items</a> object.
@@ -161,7 +163,7 @@ public @interface Items {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String minLength() default "";
+	long minLength() default -1;
 	
 	/**
 	 * <mk>maxItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#itemsObject">Items</a> object.
@@ -175,7 +177,7 @@ public @interface Items {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String maxItems() default "";
+	long maxItems() default -1;
 	
 	/**
 	 * <mk>minItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#itemsObject">Items</a> object.
@@ -189,7 +191,7 @@ public @interface Items {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String minItems() default "";
+	long minItems() default -1;
 	
 	/**
 	 * <mk>exclusiveMaximum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#itemsObject">Items</a> object.
@@ -203,7 +205,7 @@ public @interface Items {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String exclusiveMaximum() default "";
+	boolean exclusiveMaximum() default false;
 	
 	/**
 	 * <mk>exclusiveMinimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#itemsObject">Items</a> object.
@@ -217,7 +219,7 @@ public @interface Items {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String exclusiveMinimum() default "";
+	boolean exclusiveMinimum() default false;
 	
 	/**
 	 * <mk>uniqueItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#itemsObject">Items</a> object.
@@ -231,7 +233,7 @@ public @interface Items {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String uniqueItems() default "";
+	boolean uniqueItems() default false;
 	
 	/**
 	 * <mk>default</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#itemsObject">Items</a> object.
@@ -276,10 +278,15 @@ public @interface Items {
 	String $ref() default "";
 	
 	/**
+	 * TODO
+	 */
+	SubItems items() default @SubItems;
+	
+	/**
 	 * Free-form value for the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#itemsObject">Items</a> object.
 	 * 
 	 * <p>
-	 * This is a JSON object that makes up the swagger information for this field.
+	 * This is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object that makes up the swagger information for this field.
 	 * 
 	 * <p>
 	 * The following are completely equivalent ways of defining the swagger description of an Items object:
@@ -346,7 +353,7 @@ public @interface Items {
 	 * 	<li>
 	 * 		Note that the only swagger field you can't specify using this value is <js>"name"</js> whose value needs to be known during servlet initialization.
 	 * 	<li>
-	 * 		The format is a Simplified JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 		<br>The following two example are considered equivalent:
@@ -366,4 +373,5 @@ public @interface Items {
 	 * </ul>
 	 */
 	String[] value() default {};
+	
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/License.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/License.java
index f4234df..0357834 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/License.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/License.java
@@ -17,6 +17,8 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
 
+import org.apache.juneau.json.*;
+
 /**
  * Swagger schema annotation.
  * 
@@ -116,7 +118,7 @@ public @interface License {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a Simplified JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 		<br>The following two example are considered equivalent:
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/MethodSwagger.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/MethodSwagger.java
index 361587a..0495784 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/MethodSwagger.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/MethodSwagger.java
@@ -12,6 +12,8 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.rest.annotation;
 
+import org.apache.juneau.json.*;
+
 /**
  * Extended annotation for {@link RestMethod#swagger() RestMethod.swagger()}.
  * 
@@ -84,7 +86,7 @@ public @interface MethodSwagger {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is either a comma-delimited list of simple strings or a JSON array.
+	 * 		The format is either a comma-delimited list of simple strings or a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} array.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
@@ -130,7 +132,7 @@ public @interface MethodSwagger {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is either a comma-delimited list of simple strings or a JSON array.
+	 * 		The format is either a comma-delimited list of simple strings or a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} array.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
@@ -149,7 +151,7 @@ public @interface MethodSwagger {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is either a comma-delimited list of simple strings or a JSON array.
+	 * 		The format is either a comma-delimited list of simple strings or a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} array.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
@@ -299,7 +301,7 @@ public @interface MethodSwagger {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 		<br>Comments and whitespace are ignored.
 	 * 		<br>The leading and trailing <js>'{'</js>/<js>'}'</js> characters are optional.
@@ -317,7 +319,7 @@ public @interface MethodSwagger {
 	 * Free-form value for the swagger of a resource method.
 	 * 
 	 * <p>
-	 * This is a JSON object that makes up the swagger information for this resource method.
+	 * This is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object that makes up the swagger information for this resource method.
 	 * 
 	 * <p>
 	 * The following are completely equivalent ways of defining the swagger description of a resource method:
@@ -376,7 +378,7 @@ public @interface MethodSwagger {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a Simplified JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 		<br>The following two example are considered equivalent:
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Path.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Path.java
index 812c0a9..9093e06 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Path.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Path.java
@@ -17,8 +17,12 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
 
+import org.apache.juneau.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.oapi.*;
+import org.apache.juneau.json.*;
 import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.exception.*;
 
 /**
  * Annotation that can be applied to a parameter of a {@link RestMethod @RestMethod} annotated method to identify it as a variable
@@ -49,7 +53,7 @@ public @interface Path {
 	 * Specifies the {@link HttpPartParser} class used for parsing values from strings.
 	 * 
 	 * <p>
-	 * The default value for this parser is inherited from the servlet/method which defaults to {@link UonPartParser}.
+	 * The default value for this parser is inherited from the servlet/method which defaults to {@link OapiPartParser}.
 	 * <br>You can use {@link SimplePartParser} to parse POJOs that are directly convertible from <code>Strings</code>.
 	 */
 	Class<? extends HttpPartParser> parser() default HttpPartParser.Null.class;
@@ -127,28 +131,41 @@ public @interface Path {
 	 * <p>
 	 * The type of the parameter. 
 	 * 
-	 * <p>
-	 * Note that per the Swagger specification, this value is required and must be a simple type (e.g. <js>"string"</js>, <js>"number"</js>...).
-	 * <br>However, Juneau allows for arbitrarily-complex POJOs such as beans in form parameters using UON notation, this attribute can be left off in lieu of a {@link #schema()} 
-	 * attribute.
-	 * 
 	 * <p> 
 	 * The possible values are:
-	 * <ul>
-	 * 	<li><js>"string"</js>
-	 * 	<li><js>"number"</js>
-	 * 	<li><js>"integer"</js>
-	 * 	<li><js>"boolean"</js>
-	 * 	<li><js>"array"</js>
-	 * 	<li><js>"file"</js>
-	 * </ul>
-	 * 
-	 * 
-	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
+	 * 		<js>"string"</js>
+	 * 		<br>Parameter must be a string or a POJO convertible from a string.
+	 * 	<li>
+	 * 		<js>"number"</js>
+	 * 		<br>Parameter must be a number primitive or number object.
+	 * 		<br>If parameter is <code>Object</code>, creates either a <code>Float</code> or <code>Double</code> depending on the size of the number.
+	 * 	<li>
+	 * 		<js>"integer"</js>
+	 * 		<br>Parameter must be a integer/long primitive or integer/long object.
+	 * 		<br>If parameter is <code>Object</code>, creates either a <code>Short</code>, <code>Integer</code>, or <code>Long</code> depending on the size of the number.
+	 * 	<li>
+	 * 		<js>"boolean"</js>
+	 * 		<br>Parameter must be a boolean primitive or object.
+	 * 	<li>
+	 * 		<js>"array"</js>
+	 * 		<br>Parameter must be an array or collection.
+	 * 		<br>Elements must be strings or POJOs convertible from strings.
+	 * 		<br>If parameter is <code>Object</code>, creates an {@link ObjectList}.
+	 * 	<li>
+	 * 		<js>"object"</js>
+	 * 		<br>Parameter must be a map or bean.
+	 * 		<br>If parameter is <code>Object</code>, creates an {@link ObjectMap}.
+	 * 		<br>Note that this is an extension of the OpenAPI schema as Juneau allows for arbitrarily-complex POJOs to be serialized as HTTP parts.
+	 * 	<li>
+	 * 		<js>"file"</js>
+	 * 		<br>This type is currently not supported.
+	 * </ul>
+	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul class='doctree'>
+	 * 	<li class='link'><a class='doclink' href='https://swagger.io/specification/#dataTypes'>Swagger specification &gt; Data Types</a>
 	 * </ul>
 	 */
 	String type() default "";
@@ -158,194 +175,254 @@ public @interface Path {
 	 * 
 	 * <p>
 	 * The extending format for the previously mentioned <a href='https://swagger.io/specification/v2/#parameterType'>type</a>. 
-	 * See <a href='https://swagger.io/specification/v2/#dataTypeFormat'>Data Type Formats</a> for further details.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
+	 * <p> 
+	 * The possible values are:
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is plain-text.
+	 * 		<js>"int32"</js> - Signed 32 bits.
+	 * 		<br>Only valid with type <js>"integer"</js>.
 	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
+	 * 		<js>"int64"</js> - Signed 64 bits.
+	 * 		<br>Only valid with type <js>"integer"</js>.
+	 * 	<li>
+	 * 		<js>"float"</js> - 32-bit floating point number.
+	 * 		<br>Only valid with type <js>"number"</js>.
+	 * 	<li>
+	 * 		<js>"double"</js> - 64-bit floating point number.
+	 * 		<br>Only valid with type <js>"number"</js>.
+	 * 	<li>
+	 * 		<js>"byte"</js> - BASE-64 encoded characters.
+	 * 		<br>Only valid with type <js>"string"</js>.
+	 * 		<br>Parameters of type POJO convertible from string are converted after the string has been decoded.
+	 * 	<li>
+	 * 		<js>"binary"</js> - Hexadecimal encoded octets (e.g. <js>"00FF"</js>).
+	 * 		<br>Only valid with type <js>"string"</js>.
+	 * 		<br>Parameters of type POJO convertible from string are converted after the string has been decoded.
+	 * 	<li>
+	 * 		<js>"date"</js> - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 full-date</a>.
+	 * 		<br>Only valid with type <js>"string"</js>.
+	 * 	<li>
+	 * 		<js>"date-time"</js> - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 date-time</a>.
+	 * 		<br>Only valid with type <js>"string"</js>.
+	 * 	<li>
+	 * 		<js>"password"</js> - Used to hint UIs the input needs to be obscured.
+	 * 		<br>This format does not affect the serialization or parsing of the parameter.
+	 * 	<li>
+	 * 		<js>"uon"</js> - UON notation (e.g. <js>"(foo=bar,baz=@(qux,123))"</js>). 
+	 * 		<br>Only valid with type <js>"object"</js>.
+	 * 		<br>If not specified, then the input is interpreted as plain-text and is converted to a POJO directly.
+	 * </ul>
+	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul class='doctree'>
+	 * 	<li class='link'><a class='doclink' href='https://swagger.io/specification/v2/#dataTypeFormat'>Swagger specification &gt; Data Type Formats</a>
 	 * </ul>
 	 */
 	String format() default "";
 	
 	/**
-	 * <mk>pattern</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>items</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a regular expression according to the ECMA 262 regular expression dialect.
-	 * 	<li>
-	 * 		This string SHOULD be a valid regular expression.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Describes the type of items in the array.
+	 * <p>
+	 * Required if <code>type</code> is <js>"array"</js>. 
+	 * <br>Can only be used if <code>type</code> is <js>"array"</js>.
 	 */
-	String pattern() default "";
-
+	Items items() default @Items;	
+	
 	/**
 	 * <mk>collectionFormat</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
 	 * <p>
-	 * Determines the format of the array if type array is used. 
-	 * <br>Possible values are:
-	 * <ul>
-	 * 	<li><js>"csv"</js> (default) - Comma-separated values (e.g. <js>"foo,bar"</js>).
-	 * 	<li><js>"ssv"</js> - Space-separated values (e.g. <js>"foo bar"</js>).
-	 * 	<li><js>"tsv"</js> - Tab-separated values (e.g. <js>"foo\tbar"</js>).
-	 * 	<li><js>"pipes</js> - Pipe-separated values (e.g. <js>"foo|bar"</js>).
-	 * </ul>
+	 * Determines the format of the array if <code>type</code> <js>"array"</js> is used. 
+	 * <br>Can only be used if <code>type</code> is <js>"array"</js>.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
+	 * <br>Possible values are:
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
+	 * 		<js>"csv"</js> (default) - Comma-separated values (e.g. <js>"foo,bar"</js>).
+	 * 	<li>
+	 * 		<js>"ssv"</js> - Space-separated values (e.g. <js>"foo bar"</js>).
+	 * 	<li>
+	 * 		<js>"tsv"</js> - Tab-separated values (e.g. <js>"foo\tbar"</js>).
+	 * 	<li>
+	 * 		<js>"pipes</js> - Pipe-separated values (e.g. <js>"foo|bar"</js>).
+	 * 	<li>
+	 * 		<js>"multi"</js> - Corresponds to multiple parameter instances instead of multiple values for a single instance (e.g. <js>"foo=bar&amp;foo=baz"</js>). 
+	 * 	<li>
+	 * 		<js>"uon"</js> - UON notation (e.g. <js>"@(foo,bar)"</js>). 
+	 * 	<li>
 	 * </ul>
+	 * 
+	 * <p>
+	 * Note that for collections/arrays parameters with POJO element types, the input is broken into a string array before being converted into POJO elements. 
 	 */
 	String collectionFormat() default "";
 
 	/**
 	 * <mk>maximum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON number.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Defines the maximum value for a parameter of numeric types.
+	 * <br>The value must be a valid JSON number.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
 	 */
 	String maximum() default "";
 	
 	/**
-	 * <mk>minimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>exclusiveMaximum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON number.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Defines whether the maximum is matched exclusively.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
+	 * <br>If <jk>true</jk>, must be accompanied with <code>maximum</code>.
 	 */
-	String minimum() default "";
+	boolean exclusiveMaximum() default false;
 
 	/**
-	 * <mk>multipleOf</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>minimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Defines the minimum value for a parameter of numeric types.
+	 * <br>The value must be a valid JSON number.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
 	 */
-	String multipleOf() default "";
+	String minimum() default "";
 	
 	/**
-	 * <mk>maxLength</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>exclusiveMinimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Defines whether the minimum is matched exclusively.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
+	 * <br>If <jk>true</jk>, Must be accompanied with <code>minimum</code>.
 	 */
-	String maxLength() default "";
-	
+	boolean exclusiveMinimum() default false;
+
 	/**
-	 * <mk>minLength</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>maxLength</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * A string instance is valid against this keyword if its length is less than, or equal to, the value of this keyword.
+	 * <br>The length of a string instance is defined as the number of its characters as defined by <a href='https://tools.ietf.org/html/rfc4627'>RFC 4627</a>.
+	 * <br>The value <code>-1</code> is always ignored.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"string"</js>.
 	 */
-	String minLength() default "";
+	long maxLength() default -1;
 	
 	/**
-	 * <mk>exclusiveMaximum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>minLength</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
-	 */
-	String exclusiveMaximum() default "";
-
-	/**
-	 * <mk>exclusiveMinimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <p>
+	 * A string instance is valid against this keyword if its length is greater than, or equal to, the value of this keyword.
+	 * <br>The length of a string instance is defined as the number of its characters as defined by <a href='https://tools.ietf.org/html/rfc4627'>RFC 4627</a>.
+	 * <br>The value <code>-1</code> is always ignored.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"string"</js>.
 	 */
-	String exclusiveMinimum() default "";
+	long minLength() default -1;
 	
 	/**
-	 * <mk>schema</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>pattern</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON object.
-	 * 		<br>Multiple lines are concatenated with newlines.
-	 * 	<li>
-	 * 		The leading/trailing <code>{ }</code> characters are optional.
-	 * 		<br>The following two example are considered equivalent:
-	 * 		<ul>
-	 * 			<li><code>schema=<js>"{type:'string',format:'binary'}"</js></code>
-	 * 			<li><code>schema=<js>"type:'string',format:'binary'"</js></code>
-	 * 		<ul>
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * A string input is valid if it matches the specified regular expression pattern.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"string"</js>.
 	 */
-	Schema schema() default @Schema;
+	String pattern() default "";
 	
 	/**
 	 * <mk>enum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON array or comma-delimited list.
-	 * 		<br>Multiple lines are concatenated with newlines.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * If specified, the input validates successfully if it is equal to one of the elements in this array.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} array or comma-delimited list.
+	 * <br>Multiple lines are concatenated with newlines.
+	 * 
+	 * <h5 class='section'>Examples:</h5>
+	 * <p class='bcode w800'>
+	 * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/pet/findByStatus/{status}"</js>)
+	 * 	<jk>public</jk> Collection&lt;Pet&gt; findPetsByStatus(
+	 * 		<ja>@Path</ja>(
+	 * 			name=<js>"status"</js>, 
+	 * 			_enum=<js>"AVAILABLE,PENDING,SOLD"</js>,
+	 * 		) PetStatus status
+	 * 	) {...}
+	 * </p>
+	 * <p class='bcode w800'>
+	 * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/pet/findByStatus/{status}"</js>)
+	 * 	<jk>public</jk> Collection&lt;Pet&gt; findPetsByStatus(
+	 * 		<ja>@Path</ja>(
+	 * 			name=<js>"status"</js>, 
+	 * 			_enum=<js>"['AVAILABLE','PENDING','SOLD']"</js>,
+	 * 		) PetStatus status
+	 * 	) {...}
+	 * </p>
 	 */
 	String[] _enum() default {};
+
+	/**
+	 * <mk>multipleOf</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * 
+	 * <p>
+	 * A numeric instance is valid if the result of the division of the instance by this keyword's value is an integer.
+	 * <br>The value must be a valid JSON number.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
+	 */
+	String multipleOf() default "";
 	
+	//=================================================================================================================
+	// Other
+	//=================================================================================================================
+
 	/**
-	 * TODO
+	 * A serialized example of the parameter.
 	 * 
 	 * <p>
 	 * This attribute defines a JSON representation of the value that is used by {@link BasicRestInfoProvider} to construct
@@ -354,7 +431,7 @@ public @interface Path {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object or plain text string.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object or plain text string.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -367,7 +444,7 @@ public @interface Path {
 	 * Free-form value for the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
 	 * <p>
-	 * This is a JSON object that makes up the swagger information for this field.
+	 * This is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object that makes up the swagger information for this field.
 	 * 
 	 * <p>
 	 * The following are completely equivalent ways of defining the swagger description of the Path object:
@@ -417,7 +494,9 @@ public @interface Path {
 	 * 	<li>
 	 * 		Note that the only swagger field you can't specify using this value is <js>"name"</js> whose value needs to be known during servlet initialization.
 	 * 	<li>
-	 * 		The format is a Simplified JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
+	 * 	<li>
+	 * 		Automatic validation is NOT performed on input based on attributes in this value.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 		<br>The following two example are considered equivalent:
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Query.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Query.java
index f2af59e..9579472 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Query.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Query.java
@@ -16,9 +16,14 @@ import static java.lang.annotation.ElementType.*;
 import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
+import java.util.*;
 
+import org.apache.juneau.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.oapi.*;
+import org.apache.juneau.json.*;
 import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.exception.*;
 
 /**
  * Identical to {@link FormData @FormData}, but only retrieves the parameter from the URL string, not URL-encoded form
@@ -64,24 +69,10 @@ import org.apache.juneau.rest.*;
 public @interface Query {
 
 	/**
-	 * Specify <jk>true</jk> if using multi-part parameters to represent collections and arrays.
-	 * 
-	 * <p>
-	 * Normally, we expect single parameters to be specified in UON notation for representing collections of values
-	 * (e.g. <js>"&amp;key=(1,2,3)"</js>.
-	 * This annotation allows the use of multi-part parameters to represent collections
-	 * (e.g. <js>"&amp;key=1&amp;key=2&amp;key=3"</js>.
-	 * 
-	 * <p>
-	 * This setting should only be applied to Java parameters of type array or Collection.
-	 */
-	boolean multipart() default false;
-
-	/**
 	 * Specifies the {@link HttpPartParser} class used for parsing values from strings.
 	 * 
 	 * <p>
-	 * The default value for this parser is inherited from the servlet/method which defaults to {@link UonPartParser}.
+	 * The default value for this parser is inherited from the servlet/method which defaults to {@link OapiPartParser}.
 	 * <br>You can use {@link SimplePartParser} to parse POJOs that are directly convertible from <code>Strings</code>.
 	 */
 	Class<? extends HttpPartParser> parser() default HttpPartParser.Null.class;
@@ -143,18 +134,12 @@ public @interface Query {
 	 * <mk>required</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
 	 * <p>
-	 * Determines whether this parameter is mandatory. The default value is <jk>false</jk>.
-	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is boolean.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * Determines whether the parameter is mandatory.
+	 *  
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
 	 */
-	String required() default "";
+	boolean required() default false;
 	
 	//=================================================================================================================
 	// Attributes specific to parameters other than body
@@ -166,27 +151,36 @@ public @interface Query {
 	 * <p>
 	 * The type of the parameter. 
 	 * 
-	 * <p>
-	 * Note that per the Swagger specification, this value is required and must be a simple type (e.g. <js>"string"</js>, <js>"number"</js>...).
-	 * <br>However, Juneau allows for arbitrarily-complex POJOs such as beans in form parameters using UON notation, this attribute can be left off in lieu of a {@link #schema()} 
-	 * attribute.
-	 * 
 	 * <p> 
 	 * The possible values are:
-	 * <ul>
-	 * 	<li><js>"string"</js>
-	 * 	<li><js>"number"</js>
-	 * 	<li><js>"integer"</js>
-	 * 	<li><js>"boolean"</js>
-	 * 	<li><js>"array"</js>
-	 * 	<li><js>"file"</js>
-	 * </ul>
-	 * 
-	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
+	 * 		<js>"string"</js>
+	 * 		<br>Parameter must be a string or a POJO convertible from a string.
+	 * 	<li>
+	 * 		<js>"number"</js>
+	 * 		<br>Parameter must be a number primitive or number object.
+	 * 		<br>If parameter is <code>Object</code>, creates either a <code>Float</code> or <code>Double</code> depending on the size of the number.
+	 * 	<li>
+	 * 		<js>"integer"</js>
+	 * 		<br>Parameter must be a integer/long primitive or integer/long object.
+	 * 		<br>If parameter is <code>Object</code>, creates either a <code>Short</code>, <code>Integer</code>, or <code>Long</code> depending on the size of the number.
+	 * 	<li>
+	 * 		<js>"boolean"</js>
+	 * 		<br>Parameter must be a boolean primitive or object.
+	 * 	<li>
+	 * 		<js>"array"</js>
+	 * 		<br>Parameter must be an array or collection.
+	 * 		<br>Elements must be strings or POJOs convertible from strings.
+	 * 		<br>If parameter is <code>Object</code>, creates an {@link ObjectList}.
+	 * 	<li>
+	 * 		<js>"object"</js>
+	 * 		<br>Parameter must be a map or bean.
+	 * 		<br>If parameter is <code>Object</code>, creates an {@link ObjectMap}.
+	 * 		<br>Note that this is an extension of the OpenAPI schema as Juneau allows for arbitrarily-complex POJOs to be serialized as HTTP parts.
+	 * 	<li>
+	 * 		<js>"file"</js>
+	 * 		<br>This type is currently not supported.
 	 * </ul>
 	 * 
 	 * <h5 class='section'>See Also:</h5>
@@ -201,15 +195,48 @@ public @interface Query {
 	 * 
 	 * <p>
 	 * The extending format for the previously mentioned <a href='https://swagger.io/specification/v2/#parameterType'>type</a>. 
-	 * See <a href='https://swagger.io/specification/v2/#dataTypeFormat'>Data Type Formats</a> for further details.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
+	 * <p> 
+	 * The possible values are:
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is plain-text.
+	 * 		<js>"int32"</js> - Signed 32 bits.
+	 * 		<br>Only valid with type <js>"integer"</js>.
 	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
+	 * 		<js>"int64"</js> - Signed 64 bits.
+	 * 		<br>Only valid with type <js>"integer"</js>.
+	 * 	<li>
+	 * 		<js>"float"</js> - 32-bit floating point number.
+	 * 		<br>Only valid with type <js>"number"</js>.
+	 * 	<li>
+	 * 		<js>"double"</js> - 64-bit floating point number.
+	 * 		<br>Only valid with type <js>"number"</js>.
+	 * 	<li>
+	 * 		<js>"byte"</js> - BASE-64 encoded characters.
+	 * 		<br>Only valid with type <js>"string"</js>.
+	 * 		<br>Parameters of type POJO convertible from string are converted after the string has been decoded.
+	 * 	<li>
+	 * 		<js>"binary"</js> - Hexadecimal encoded octets (e.g. <js>"00FF"</js>).
+	 * 		<br>Only valid with type <js>"string"</js>.
+	 * 		<br>Parameters of type POJO convertible from string are converted after the string has been decoded.
+	 * 	<li>
+	 * 		<js>"date"</js> - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 full-date</a>.
+	 * 		<br>Only valid with type <js>"string"</js>.
+	 * 	<li>
+	 * 		<js>"date-time"</js> - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 date-time</a>.
+	 * 		<br>Only valid with type <js>"string"</js>.
+	 * 	<li>
+	 * 		<js>"password"</js> - Used to hint UIs the input needs to be obscured.
+	 * 		<br>This format does not affect the serialization or parsing of the parameter.
+	 * 	<li>
+	 * 		<js>"uon"</js> - UON notation (e.g. <js>"(foo=bar,baz=@(qux,123))"</js>). 
+	 * 		<br>Only valid with type <js>"object"</js>.
+	 * 		<br>If not specified, then the input is interpreted as plain-text and is converted to a POJO directly.
+	 * </ul>
+	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul class='doctree'>
+	 * 	<li class='link'><a class='doclink' href='https://swagger.io/specification/v2/#dataTypeFormat'>Swagger specification &gt; Data Type Formats</a>
 	 * </ul>
 	 */
 	String format() default "";
@@ -220,270 +247,280 @@ public @interface Query {
 	 * <p>
 	 * Sets the ability to pass empty-valued parameters. 
 	 * <br>This is valid only for either query or formData parameters and allows you to send a parameter with a name only or an empty value. 
-	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is boolean.
-	 * 	<li>
-	 * 		Default value is <jk>false</jk>.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * The default value is <jk>false</jk>.
 	 */
-	String allowEmptyValue() default "";
+	boolean allowEmptyValue() default false;
 
 	/**
-	 * <mk>pattern</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>items</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a regular expression according to the ECMA 262 regular expression dialect.
-	 * 	<li>
-	 * 		This string SHOULD be a valid regular expression.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Describes the type of items in the array.
+	 * <p>
+	 * Required if <code>type</code> is <js>"array"</js>. 
+	 * <br>Can only be used if <code>type</code> is <js>"array"</js>.
 	 */
-	String pattern() default "";
+	Items items() default @Items;	
 
 	/**
 	 * <mk>collectionFormat</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
 	 * <p>
-	 * Determines the format of the array if type array is used. 
-	 * <br>Possible values are:
-	 * <ul>
-	 * 	<li><js>"csv"</js> (default) - Comma-separated values (e.g. <js>"foo,bar"</js>).
-	 * 	<li><js>"ssv"</js> - Space-separated values (e.g. <js>"foo bar"</js>).
-	 * 	<li><js>"tsv"</js> - Tab-separated values (e.g. <js>"foo\tbar"</js>).
-	 * 	<li><js>"pipes</js> - Pipe-separated values (e.g. <js>"foo|bar"</js>).
-	 * 	<li><js>"multi"</js> - Corresponds to multiple parameter instances instead of multiple values for a single instance (e.g. <js>"foo=bar&amp;foo=baz"</js>). 
-	 * </ul>
+	 * Determines the format of the array if <code>type</code> <js>"array"</js> is used. 
+	 * <br>Can only be used if <code>type</code> is <js>"array"</js>.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
+	 * <br>Possible values are:
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
+	 * 		<js>"csv"</js> (default) - Comma-separated values (e.g. <js>"foo,bar"</js>).
+	 * 	<li>
+	 * 		<js>"ssv"</js> - Space-separated values (e.g. <js>"foo bar"</js>).
+	 * 	<li>
+	 * 		<js>"tsv"</js> - Tab-separated values (e.g. <js>"foo\tbar"</js>).
+	 * 	<li>
+	 * 		<js>"pipes</js> - Pipe-separated values (e.g. <js>"foo|bar"</js>).
+	 * 	<li>
+	 * 		<js>"multi"</js> - Corresponds to multiple parameter instances instead of multiple values for a single instance (e.g. <js>"foo=bar&amp;foo=baz"</js>). 
+	 * 	<li>
+	 * 		<js>"uon"</js> - UON notation (e.g. <js>"@(foo,bar)"</js>). 
 	 * </ul>
+	 * 
+	 * <p>
+	 * Note that for collections/arrays parameters with POJO element types, the input is broken into a string array before being converted into POJO elements. 
 	 */
 	String collectionFormat() default "";
 
 	/**
+	 * <mk>default</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * 
+	 * <p>
+	 * Declares the value of the parameter that the server will use if none is provided, for example a "count" to control the number of results per page might default to 100 if not supplied by the client in the request. 
+	 * <br>(Note: "default" has no meaning for required parameters.) 
+	 * 
+	 * <p>
+	 * Additionally, this value is used to create instances of POJOs that are then serialized as language-specific examples in the generated Swagger documentation
+	 * if the examples are not defined in some other way.
+	 * 
+	 * <p>
+	 * The format of this value is a string.
+	 * <br>Multiple lines are concatenated with newlines.
+	 * 
+	 * <h5 class='section'>Examples:</h5>
+	 * <p class='bcode w800'>
+	 * 	<jk>public</jk> Order placeOrder(
+	 * 		<jk>@Query</jk>(name=<js>"petId"</jk>, _default=<js>"100"</js>) <jk>long</jk> petId,
+	 * 		<jk>@Query</jk>(name=<js>"additionalInfo"</jk>, format=<js>"uon"</js>, _default=<js>"(rushOrder=false)"</js>) AdditionalInfo additionalInfo,
+	 * 		<jk>@Query</jk>(name=<js>"flags"</jk>, collectionFormat=<js>"uon"</js>, _default=<js>"@(new-customer)"</js>) String[] flags
+	 * 	) {...}
+	 * </p>
+	 */
+	String[] _default() default {};
+	
+	/**
 	 * <mk>maximum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON number.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Defines the maximum value for a parameter of numeric types.
+	 * <br>The value must be a valid JSON number.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
 	 */
 	String maximum() default "";
 	
 	/**
+	 * <mk>exclusiveMaximum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * 
+	 * <p>
+	 * Defines whether the maximum is matched exclusively.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
+	 * <br>If <jk>true</jk>, must be accompanied with <code>maximum</code>.
+	 */
+	boolean exclusiveMaximum() default false;
+
+	/**
 	 * <mk>minimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON number.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Defines the minimum value for a parameter of numeric types.
+	 * <br>The value must be a valid JSON number.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
 	 */
 	String minimum() default "";
-
+	
 	/**
-	 * <mk>multipleOf</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>exclusiveMinimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Defines whether the minimum is matched exclusively.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
+	 * <br>If <jk>true</jk>, Must be accompanied with <code>minimum</code>.
 	 */
-	String multipleOf() default "";
+	boolean exclusiveMinimum() default false;
 	
 	/**
 	 * <mk>maxLength</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * A string instance is valid against this keyword if its length is less than, or equal to, the value of this keyword.
+	 * <br>The length of a string instance is defined as the number of its characters as defined by <a href='https://tools.ietf.org/html/rfc4627'>RFC 4627</a>.
+	 * <br>The value <code>-1</code> is always ignored.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"string"</js>.
 	 */
-	String maxLength() default "";
+	long maxLength() default -1;
 	
 	/**
 	 * <mk>minLength</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * A string instance is valid against this keyword if its length is greater than, or equal to, the value of this keyword.
+	 * <br>The length of a string instance is defined as the number of its characters as defined by <a href='https://tools.ietf.org/html/rfc4627'>RFC 4627</a>.
+	 * <br>The value <code>-1</code> is always ignored.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"string"</js>.
 	 */
-	String minLength() default "";
+	long minLength() default -1;
 	
 	/**
-	 * <mk>maxItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>pattern</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
-	 */
-	String maxItems() default "";
-
-	/**
-	 * <mk>minItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <p>
+	 * A string input is valid if it matches the specified regular expression pattern.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"string"</js>.
 	 */
-	String minItems() default "";
+	String pattern() default "";
 
 	/**
-	 * <mk>exclusiveMaximum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>maxItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * An array or collection is valid if its size is less than, or equal to, the value of this keyword.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"array"</js>.
 	 */
-	String exclusiveMaximum() default "";
+	long maxItems() default -1;
 
 	/**
-	 * <mk>exclusiveMinimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>minItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is numeric.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
-	 */
-	String exclusiveMinimum() default "";
-	
-	/**
-	 * <mk>uniqueItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <p>
+	 * An array or collection is valid if its size is greater than, or equal to, the value of this keyword.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is boolean.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
-	 */
-	String uniqueItems() default "";
-	
-	/**
-	 * <mk>schema</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON object.
-	 * 		<br>Multiple lines are concatenated with newlines.
-	 * 	<li>
-	 * 		The leading/trailing <code>{ }</code> characters are optional.
-	 * 		<br>The following two example are considered equivalent:
-	 * 		<ul>
-	 * 			<li><code>schema=<js>"{type:'string',format:'binary'}"</js></code>
-	 * 			<li><code>schema=<js>"type:'string',format:'binary'"</js></code>
-	 * 		<ul>
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * Only allowed for the following types: <js>"array"</js>.
 	 */
-	Schema schema() default @Schema;
-	
+	long minItems() default -1;
+
 	/**
-	 * <mk>default</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>uniqueItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
 	 * <p>
-	 * Additionally, this method can be used to define a default value for a missing query entry.
+	 * If <jk>true</jk> the input validates successfully if all of its elements are unique.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is any JSON.
-	 * 		<br>Multiple lines are concatenated with newlines.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * <br>If the parameter type is a subclass of {@link Set}, this validation is skipped (since a set can only contain unique items anyway).
+	 * <br>Otherwise, the collection or array is checked for duplicate items.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"array"</js>.
 	 */
-	String[] _default() default {};
-	
+	boolean uniqueItems() default false;
+
 	/**
 	 * <mk>enum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON array or comma-delimited list.
-	 * 		<br>Multiple lines are concatenated with newlines.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * If specified, the input validates successfully if it is equal to one of the elements in this array.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} array or comma-delimited list.
+	 * <br>Multiple lines are concatenated with newlines.
+	 * 
+	 * <h5 class='section'>Examples:</h5>
+	 * <p class='bcode w800'>
+	 * 	<jk>public</jk> Collection&lt;Pet&gt; findPetsByStatus(
+	 * 		<ja>@Query</ja>(
+	 * 			name=<js>"status"</js>, 
+	 * 			_enum=<js>"AVAILABLE,PENDING,SOLD"</js>,
+	 * 		) PetStatus status
+	 * 	) {...}
+	 * </p>
+	 * <p class='bcode w800'>
+	 * 	<jk>public</jk> Collection&lt;Pet&gt; findPetsByStatus(
+	 * 		<ja>@Query</ja>(
+	 * 			name=<js>"status"</js>, 
+	 * 			_enum=<js>"['AVAILABLE','PENDING','SOLD']"</js>,
+	 * 		) PetStatus status
+	 * 	) {...}
+	 * </p>
 	 */
 	String[] _enum() default {};
 	
 	/**
-	 * <mk>items</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
+	 * <mk>multipleOf</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul class='spaced-list'>
-	 * 	<li>
-	 * 		The format is a JSON object.
-	 * 	<li>
-	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
-	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
-	 * </ul>
+	 * <p>
+	 * A numeric instance is valid if the result of the division of the instance by this keyword's value is an integer.
+	 * <br>The value must be a valid JSON number.
+	 * 
+	 * <p>
+	 * If validation is not met, the method call will throw a {@link BadRequest}.
+	 * 
+	 * <p>
+	 * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
 	 */
-	Items items() default @Items;	
+	String multipleOf() default "";
+
+	//=================================================================================================================
+	// Other
+	//=================================================================================================================
 	
 	/**
-	 * TODO
+	 * A serialized example of the parameter.
 	 * 
 	 * <p>
 	 * This attribute defines a JSON representation of the value that is used by {@link BasicRestInfoProvider} to construct
@@ -492,7 +529,7 @@ public @interface Query {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object or plain text string.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object or plain text string.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -505,7 +542,7 @@ public @interface Query {
 	 * Free-form value for the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#parameterObject">Parameter</a> object.
 	 * 
 	 * <p>
-	 * This is a JSON object that makes up the swagger information for this field.
+	 * This is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object that makes up the swagger information for this field.
 	 * 
 	 * <p>
 	 * The following are completely equivalent ways of defining the swagger description of the Query object:
@@ -565,7 +602,9 @@ public @interface Query {
 	 * 	<li>
 	 * 		Note that the only swagger field you can't specify using this value is <js>"name"</js> whose value needs to be known during servlet initialization.
 	 * 	<li>
-	 * 		The format is a Simplified JSON object.
+	 * 		Automatic validation is NOT performed on input based on attributes in this value.
+	 * 	<li>
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 		<br>The following two example are considered equivalent:
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResourceSwagger.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResourceSwagger.java
index 1df8975..327cad6 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResourceSwagger.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResourceSwagger.java
@@ -12,6 +12,8 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.rest.annotation;
 
+import org.apache.juneau.json.*;
+
 /**
  * Extended annotation for {@link RestResource#swagger() @RestResource.swagger()}.
  * 
@@ -96,7 +98,7 @@ public @interface ResourceSwagger {
 	 * Defines the swagger field <code>/info/contact</code>.
 	 * 
 	 * <p>
-	 * A simplified JSON string with the following fields:
+	 * A {@link JsonSerializer#DEFAULT_LAX Simple-JSON} string with the following fields:
 	 * <p class='bcode'>
 	 * 	{
 	 * 		name: string,
@@ -139,7 +141,7 @@ public @interface ResourceSwagger {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -177,7 +179,7 @@ public @interface ResourceSwagger {
 	 * It is used to populate the Swagger license field and to display on HTML pages.
 	 * 
 	 * <p>
-	 * A simplified JSON string with the following fields:
+	 * A {@link JsonSerializer#DEFAULT_LAX Simple-JSON} string with the following fields:
 	 * <p class='bcode'>
 	 * 	{
 	 * 		name: string,
@@ -202,7 +204,7 @@ public @interface ResourceSwagger {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -221,7 +223,7 @@ public @interface ResourceSwagger {
 	 * It is used to populate the Swagger tags field and to display on HTML pages.
 	 * 
 	 * <p>
-	 * A simplified JSON string with the following fields:
+	 * A {@link JsonSerializer#DEFAULT_LAX Simple-JSON} string with the following fields:
 	 * <p class='bcode'>
 	 * 	[
 	 * 		{
@@ -252,7 +254,7 @@ public @interface ResourceSwagger {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON array.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} array.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -315,7 +317,7 @@ public @interface ResourceSwagger {
 	 * Free-form value for the swagger of a resource.
 	 * 
 	 * <p>
-	 * This is a JSON object that makes up the swagger information for this resource.
+	 * This is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object that makes up the swagger information for this resource.
 	 * 
 	 * <p>
 	 * The following are completely equivalent ways of defining the swagger description of a resource:
@@ -405,7 +407,7 @@ public @interface ResourceSwagger {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a Simplified JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 		<br>The following two example are considered equivalent:
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Response.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Response.java
index 2e357c3..aae3f7b 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Response.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Response.java
@@ -17,6 +17,7 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
 
+import org.apache.juneau.json.*;
 import org.apache.juneau.rest.exception.*;
 import org.apache.juneau.rest.helper.*;
 
@@ -157,7 +158,7 @@ public @interface Response {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
@@ -184,7 +185,7 @@ public @interface Response {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is any JSON.
+	 * 		The format is any {@link JsonSerializer#DEFAULT_LAX Simple-JSON}.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
@@ -204,12 +205,12 @@ public @interface Response {
 	 * TODO
 	 * 
 	 * <p>
-	 * The format is a JSON object with keys as media types and values as string representations of the body response.
+	 * The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object with keys as media types and values as string representations of the body response.
 	 * 
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
@@ -224,7 +225,7 @@ public @interface Response {
 	 * Free-form value for the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#responseObject">Response</a> object.
 	 * 
 	 * <p>
-	 * This is a JSON object that makes up the swagger information for this field.
+	 * This is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object that makes up the swagger information for this field.
 	 * 
 	 * <p>
 	 * The following are completely equivalent ways of defining the swagger description of the Response object:
@@ -281,7 +282,7 @@ public @interface Response {
 	 * 	<li>
 	 * 		Note that the only swagger field you can't specify using this value is <js>"code"</js> whose value needs to be known during servlet initialization.
 	 * 	<li>
-	 * 		The format is a Simplified JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 		<br>The following two example are considered equivalent:
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResponseHeader.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResponseHeader.java
index 04d9c54..d8e403b 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResponseHeader.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResponseHeader.java
@@ -18,6 +18,8 @@ import static java.lang.annotation.RetentionPolicy.*;
 import java.lang.annotation.*;
 
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.oapi.*;
+import org.apache.juneau.json.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.utils.*;
 
@@ -129,7 +131,7 @@ public @interface ResponseHeader {
 	 * Specifies the {@link HttpPartSerializer} class used for serializing values.
 	 * 
 	 * <p>
-	 * The default value for this parser is inherited from the servlet/method which defaults to {@link SimpleUonPartSerializer}.
+	 * The default value for this parser is inherited from the servlet/method which defaults to {@link OapiPartSerializer}.
 	 */
 	Class<? extends HttpPartSerializer> serializer() default HttpPartSerializer.Null.class;
 
@@ -289,7 +291,7 @@ public @interface ResponseHeader {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String maxLength() default "";
+	long maxLength() default -1;
 	
 	/**
 	 * <mk>minLength</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#headerObject">Header</a> object.
@@ -303,7 +305,7 @@ public @interface ResponseHeader {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String minLength() default "";
+	long minLength() default -1;
 	
 	/**
 	 * <mk>maxItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#headerObject">Header</a> object.
@@ -317,7 +319,7 @@ public @interface ResponseHeader {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String maxItems() default "";
+	long maxItems() default -1;
 	
 	/**
 	 * <mk>minItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#headerObject">Header</a> object.
@@ -331,7 +333,7 @@ public @interface ResponseHeader {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String minItems() default "";
+	long minItems() default -1;
 	
 	/**
 	 * <mk>exclusiveMaximum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#headerObject">Header</a> object.
@@ -345,7 +347,7 @@ public @interface ResponseHeader {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String exclusiveMaximum() default "";
+	boolean exclusiveMaximum() default false;
 	
 	/**
 	 * <mk>exclusiveMinimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#headerObject">Header</a> object.
@@ -359,7 +361,7 @@ public @interface ResponseHeader {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String exclusiveMinimum() default "";
+	boolean exclusiveMinimum() default false;
 	
 	/**
 	 * <mk>uniqueItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#headerObject">Header</a> object.
@@ -373,7 +375,7 @@ public @interface ResponseHeader {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String uniqueItems() default "";
+	boolean uniqueItems() default false;
 	
 	/**
 	 * <mk>items</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#headerObject">Header</a> object.
@@ -381,7 +383,7 @@ public @interface ResponseHeader {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -396,7 +398,7 @@ public @interface ResponseHeader {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is any JSON.
+	 * 		The format is any {@link JsonSerializer#DEFAULT_LAX Simple-JSON}.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -411,7 +413,7 @@ public @interface ResponseHeader {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON array or comma-delimited list.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} array or comma-delimited list.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -430,7 +432,7 @@ public @interface ResponseHeader {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object or plain text string.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object or plain text string.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -491,7 +493,7 @@ public @interface ResponseHeader {
 	 * 	<li>
 	 * 		Note that the only swagger field you can't specify using this value is <js>"name"</js> whose value needs to be known during servlet initialization.
 	 * 	<li>
-	 * 		The format is a Simplified JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 		<br>The following two example are considered equivalent:
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResponseStatus.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResponseStatus.java
index 66021b2..5dec704 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResponseStatus.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResponseStatus.java
@@ -16,6 +16,7 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
 
+import org.apache.juneau.json.*;
 import org.apache.juneau.utils.*;
 
 /**
@@ -188,7 +189,7 @@ public @interface ResponseStatus {
 	 * 	<li>
 	 * 		Note that the only swagger field you can't specify using this value is <js>"code"</js> whose value needs to be known during servlet initialization.
 	 * 	<li>
-	 * 		The format is a Simplified JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 		<br>The following two example are considered equivalent:
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java
index 85d524b..c3ac989 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java
@@ -18,6 +18,7 @@ import static java.lang.annotation.RetentionPolicy.*;
 import java.lang.annotation.*;
 
 import org.apache.juneau.*;
+import org.apache.juneau.json.*;
 import org.apache.juneau.remoteable.*;
 import org.apache.juneau.rest.*;
 
@@ -758,7 +759,7 @@ public @interface RestMethod {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is JSON.
+	 * 		The format is {@link JsonSerializer#DEFAULT_LAX Simple-JSON}.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		The starting and ending <js>'{'</js>/<js>'}'</js> characters around the entire value are optional.
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
index 4e694b0..6364285 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
@@ -21,6 +21,7 @@ import org.apache.juneau.*;
 import org.apache.juneau.config.*;
 import org.apache.juneau.encoders.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.httppart.uon.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.serializer.*;
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Schema.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Schema.java
index 6c71ebd..f14e2c6 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Schema.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Schema.java
@@ -17,6 +17,7 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
 
+import org.apache.juneau.json.*;
 import org.apache.juneau.rest.*;
 
 /**
@@ -141,7 +142,7 @@ public @interface Schema {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is any JSON.
+	 * 		The format is any {@link JsonSerializer#DEFAULT_LAX Simple-JSON}.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -190,7 +191,7 @@ public @interface Schema {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String exclusiveMaximum() default "";
+	boolean exclusiveMaximum() default false;
 
 	/**
 	 * <mk>minimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#schemaObject">Schema</a> object.
@@ -218,7 +219,7 @@ public @interface Schema {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String exclusiveMinimum() default "";
+	boolean exclusiveMinimum() default false;
 	
 	/**
 	 * <mk>maxLength</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#schemaObject">Schema</a> object.
@@ -232,7 +233,7 @@ public @interface Schema {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String maxLength() default "";
+	long maxLength() default -1;
 	
 	/**
 	 * <mk>minLength</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#schemaObject">Schema</a> object.
@@ -246,7 +247,7 @@ public @interface Schema {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String minLength() default "";
+	long minLength() default -1;
 	
 	/**
 	 * <mk>pattern</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#schemaObject">Schema</a> object.
@@ -282,7 +283,7 @@ public @interface Schema {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String maxItems() default "";
+	long maxItems() default -1;
 
 	/**
 	 * <mk>minItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#schemaObject">Schema</a> object.
@@ -296,7 +297,7 @@ public @interface Schema {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String minItems() default "";
+	long minItems() default -1;
 
 	/**
 	 * <mk>uniqueItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#schemaObject">Schema</a> object.
@@ -310,7 +311,7 @@ public @interface Schema {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String uniqueItems() default "";
+	boolean uniqueItems() default false;
 	
 	
 	/**
@@ -319,7 +320,7 @@ public @interface Schema {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -335,7 +336,7 @@ public @interface Schema {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -377,7 +378,7 @@ public @interface Schema {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String required() default "";
+	boolean required() default false;
 	
 	/**
 	 * <mk>enum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#schemaObject">Schema</a> object.
@@ -385,7 +386,7 @@ public @interface Schema {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON array or comma-delimited list.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} array or comma-delimited list.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -448,7 +449,7 @@ public @interface Schema {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -463,7 +464,7 @@ public @interface Schema {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -478,7 +479,7 @@ public @interface Schema {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -493,7 +494,7 @@ public @interface Schema {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -508,7 +509,7 @@ public @interface Schema {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -523,14 +524,14 @@ public @interface Schema {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String readOnly() default "";
+	boolean readOnly() default false;
 	
 	/**
 	 * <mk>xml</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#schemaObject">Schema</a> object.
@@ -538,7 +539,7 @@ public @interface Schema {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -553,7 +554,7 @@ public @interface Schema {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -572,7 +573,7 @@ public @interface Schema {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object or plain text string.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object or plain text string.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -590,7 +591,7 @@ public @interface Schema {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -599,6 +600,9 @@ public @interface Schema {
 	 */
 	String[] examples() default {};
 
+	/**
+	 * TODO
+	 */
 	boolean ignore() default false;
 	
 	/**
@@ -646,7 +650,7 @@ public @interface Schema {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a Simplified JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 		<br>The following two example are considered equivalent:
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Items.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/SubItems.java
similarity index 93%
copy from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Items.java
copy to juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/SubItems.java
index 3c881d7..1fed64c 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Items.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/SubItems.java
@@ -17,6 +17,8 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
 
+import org.apache.juneau.json.*;
+
 /**
  * Swagger schema annotation.
  * 
@@ -35,7 +37,7 @@ import java.lang.annotation.*;
 @Target({PARAMETER,TYPE})
 @Retention(RUNTIME)
 @Inherited
-public @interface Items {
+public @interface SubItems {
 	
 	/**
 	 * <mk>type</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#itemsObject">Items</a> object.
@@ -147,7 +149,7 @@ public @interface Items {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String maxLength() default "";
+	long maxLength() default -1;
 	
 	/**
 	 * <mk>minLength</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#itemsObject">Items</a> object.
@@ -161,7 +163,7 @@ public @interface Items {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String minLength() default "";
+	long minLength() default -1;
 	
 	/**
 	 * <mk>maxItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#itemsObject">Items</a> object.
@@ -175,7 +177,7 @@ public @interface Items {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String maxItems() default "";
+	long maxItems() default -1;
 	
 	/**
 	 * <mk>minItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#itemsObject">Items</a> object.
@@ -189,7 +191,7 @@ public @interface Items {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String minItems() default "";
+	long minItems() default -1;
 	
 	/**
 	 * <mk>exclusiveMaximum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#itemsObject">Items</a> object.
@@ -203,7 +205,7 @@ public @interface Items {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String exclusiveMaximum() default "";
+	boolean exclusiveMaximum() default false;
 	
 	/**
 	 * <mk>exclusiveMinimum</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#itemsObject">Items</a> object.
@@ -217,7 +219,7 @@ public @interface Items {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String exclusiveMinimum() default "";
+	boolean exclusiveMinimum() default false;
 	
 	/**
 	 * <mk>uniqueItems</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#itemsObject">Items</a> object.
@@ -231,7 +233,7 @@ public @interface Items {
 	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
 	 * </ul>
 	 */
-	String uniqueItems() default "";
+	boolean uniqueItems() default false;
 	
 	/**
 	 * <mk>default</mk> field of the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#itemsObject">Items</a> object.
@@ -279,7 +281,7 @@ public @interface Items {
 	 * Free-form value for the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#itemsObject">Items</a> object.
 	 * 
 	 * <p>
-	 * This is a JSON object that makes up the swagger information for this field.
+	 * This is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object that makes up the swagger information for this field.
 	 * 
 	 * <p>
 	 * The following are completely equivalent ways of defining the swagger description of an Items object:
@@ -346,7 +348,7 @@ public @interface Items {
 	 * 	<li>
 	 * 		Note that the only swagger field you can't specify using this value is <js>"name"</js> whose value needs to be known during servlet initialization.
 	 * 	<li>
-	 * 		The format is a Simplified JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 		<br>The following two example are considered equivalent:
@@ -366,4 +368,9 @@ public @interface Items {
 	 * </ul>
 	 */
 	String[] value() default {};
+	
+	/**
+	 * TODO
+	 */
+	String[] items() default {};
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Tag.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Tag.java
index 356e5bf..2f4aa58 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Tag.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Tag.java
@@ -17,6 +17,8 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
 
+import org.apache.juneau.json.*;
+
 /**
  * Swagger schema annotation.
  * 
@@ -83,7 +85,7 @@ public @interface Tag {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -98,7 +100,7 @@ public @interface Tag {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 		<br>Multiple lines are concatenated with newlines.
 	 * 	<li>
 	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time and request-time variables</a> 
@@ -111,7 +113,7 @@ public @interface Tag {
 	 * Free-form value for the Swagger <a class="doclink" href="https://swagger.io/specification/v2/#tagObject">Tag</a> object.
 	 * 
 	 * <p>
-	 * This is a JSON object that makes up the swagger information for this Tag object.
+	 * This is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object that makes up the swagger information for this Tag object.
 	 * 
 	 * <p>
 	 * The following are completely equivalent ways of defining the swagger description of the resource tags:
@@ -174,7 +176,7 @@ public @interface Tag {
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		The format is a Simplified JSON object.
+	 * 		The format is a {@link JsonSerializer#DEFAULT_LAX Simple-JSON} object.
 	 * 	<li>
 	 * 		The leading/trailing <code>{ }</code> characters are optional.
 	 * 		<br>The following two example are considered equivalent:
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockRest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockRest.java
index 20de6fd..9165424 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockRest.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockRest.java
@@ -54,9 +54,9 @@ public class MockRest implements MockHttpConnection {
 
 	private final RestContext rc;
 	
-	private MockRest(Class<?> c) throws Exception {
+	private MockRest(Class<?> c, boolean debug) throws Exception {
 		if (! CONTEXTS.containsKey(c))
-			CONTEXTS.put(c, RestContext.create(c.newInstance()).build().postInit().postInitChildFirst());
+			CONTEXTS.put(c, RestContext.create(c.newInstance()).logger(debug ? BasicRestLogger.class : NoOpRestLogger.class).build().postInit().postInitChildFirst());
 		rc = CONTEXTS.get(c);
 	}
 	
@@ -69,13 +69,28 @@ public class MockRest implements MockHttpConnection {
 	 * 	For testing conveniences, this method wraps all exceptions in a RuntimeException so that you can easily define mocks as reusable fields. 
 	 */
 	public static MockRest create(Class<?> c) throws RuntimeException {
+		return create(c, false);
+	}
+	
+	/**
+	 * Create a new mock REST interface 
+	 * 
+	 * @param c The REST class.
+	 * @param debug 
+	 * 	If <jk>true</jk>, the REST interface will use the {@link BasicRestLogger} for logging.
+	 * 	<br>Otherwise, uses {@link NoOpRestLogger}.
+	 * @return A new mock interface.
+	 * @throws RuntimeException 
+	 * 	For testing conveniences, this method wraps all exceptions in a RuntimeException so that you can easily define mocks as reusable fields. 
+	 */
+	public static MockRest create(Class<?> c, boolean debug) throws RuntimeException {
 		try {
-			return new MockRest(c);
+			return new MockRest(c, debug);
 		} catch (Exception e) {
 			throw new RuntimeException(e);
 		}
 	}
-	
+
 	/**
 	 * Performs a REST request against the REST interface.
 	 * 
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
index d3811b2..b55aef8 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
@@ -794,9 +794,9 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
 	public String getPathInfo() {
 		if (pathInfo == null) {
 			pathInfo = getRequestURI();
-			if (! isEmpty(contextPath))
+			if (isNotEmpty(contextPath))
 				pathInfo = pathInfo.substring(contextPath.length());
-			if (! isEmpty(servletPath))
+			if (isNotEmpty(servletPath))
 				pathInfo = pathInfo.substring(servletPath.length());
 		}
 		return nullIfEmpty(urlDecode(pathInfo));
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/AnnotationUtils.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/AnnotationUtils.java
index 5c9cf72..625a258 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/AnnotationUtils.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/AnnotationUtils.java
@@ -47,7 +47,7 @@ public class AnnotationUtils {
 		return om
 			.appendSkipEmpty("_value", joinnl(a.value()))
 			.appendSkipEmpty("description", joinnl(a.description()))
-			.appendSkipEmpty("required", a.required())
+			.appendSkipFalse("required", a.required())
 			.appendSkipEmpty("example", joinnl(a.example()))
 			.appendSkipEmpty("examples", joinnl(a.examples()))
 			.appendSkipEmpty("schema", merge(om.getObjectMap("schema"), a.schema()));
@@ -81,6 +81,7 @@ public class AnnotationUtils {
 		if (empty(a))
 			return om;
 		om = newMap(om);
+		a._enum();
 		return om
 			.appendSkipEmpty("_value", joinnl(a.value()))
 			.appendSkipEmpty("$ref", a.$ref())
@@ -90,18 +91,18 @@ public class AnnotationUtils {
 			.appendSkipEmpty("default", joinnl(a._default()))
 			.appendSkipEmpty("multipleOf", a.multipleOf())
 			.appendSkipEmpty("maximum", a.maximum())
-			.appendSkipEmpty("exclusiveMaximum", a.exclusiveMaximum())
+			.appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum())
 			.appendSkipEmpty("minimum", a.minimum())
-			.appendSkipEmpty("exclusiveMinimum", a.exclusiveMinimum())
-			.appendSkipEmpty("maxLength", a.maxLength())
-			.appendSkipEmpty("minLength", a.minLength())
+			.appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum())
+			.appendSkipMinusOne("maxLength", a.maxLength())
+			.appendSkipMinusOne("minLength", a.minLength())
 			.appendSkipEmpty("pattern", a.pattern())
-			.appendSkipEmpty("maxItems", a.maxItems())
-			.appendSkipEmpty("minItems", a.minItems())
-			.appendSkipEmpty("uniqueItems", a.uniqueItems())
+			.appendSkipMinusOne("maxItems", a.maxItems())
+			.appendSkipMinusOne("minItems", a.minItems())
+			.appendSkipFalse("uniqueItems", a.uniqueItems())
 			.appendSkipEmpty("maxProperties", a.maxProperties())
 			.appendSkipEmpty("minProperties", a.minProperties())
-			.appendSkipEmpty("required", a.required())
+			.appendSkipFalse("required", a.required())
 			.appendSkipEmpty("enum", joinnl(a._enum()))
 			.appendSkipEmpty("type", a.type())
 			.appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items()))
@@ -109,7 +110,7 @@ public class AnnotationUtils {
 			.appendSkipEmpty("properties", joinnl(a.properties()))
 			.appendSkipEmpty("additionalProperties", joinnl(a.additionalProperties()))
 			.appendSkipEmpty("discriminator", a.discriminator())
-			.appendSkipEmpty("readOnly", a.readOnly())
+			.appendSkipFalse("readOnly", a.readOnly())
 			.appendSkipEmpty("xml", joinnl(a.xml()))
 			.appendSkipEmpty("externalDocs", merge(om.getObjectMap("externalDocs"), a.externalDocs()))
 			.appendSkipEmpty("example", joinnl(a.example()))
@@ -178,15 +179,51 @@ public class AnnotationUtils {
 			.appendSkipEmpty("maximum", a.maximum())
 			.appendSkipEmpty("minimum", a.minimum())
 			.appendSkipEmpty("multipleOf", a.multipleOf())
-			.appendSkipEmpty("maxLength", a.maxLength())
-			.appendSkipEmpty("minLength", a.minLength())
-			.appendSkipEmpty("maxItems", a.maxItems())
-			.appendSkipEmpty("minItems", a.minItems())
-			.appendSkipEmpty("exclusiveMaximum", a.exclusiveMaximum())
-			.appendSkipEmpty("exclusiveMinimum", a.exclusiveMinimum())
-			.appendSkipEmpty("uniqueItems", a.uniqueItems())
+			.appendSkipMinusOne("maxLength", a.maxLength())
+			.appendSkipMinusOne("minLength", a.minLength())
+			.appendSkipMinusOne("maxItems", a.maxItems())
+			.appendSkipMinusOne("minItems", a.minItems())
+			.appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum())
+			.appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum())
+			.appendSkipFalse("uniqueItems", a.uniqueItems())
 			.appendSkipEmpty("default", joinnl(a._default()))
-			.appendSkipEmpty("enum", joinnl(a._enum()));
+			.appendSkipEmpty("enum", joinnl(a._enum()))
+			.appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items()))
+			;
+	}	
+
+	/**
+	 * Merges the contents of the specified annotation into the specified map.
+	 * 
+	 * @param om The map to add the annotation values to.
+	 * @param a The annotation.
+	 * @return The same map with merged results, or a new map if the map was <jk>null</jk>.
+	 */
+	public static ObjectMap merge(ObjectMap om, SubItems a) {
+		if (empty(a))
+			return om;
+		om = newMap(om);
+		return om
+			.appendSkipEmpty("_value", joinnl(a.value()))
+			.appendSkipEmpty("type", a.type())
+			.appendSkipEmpty("format", a.format())
+			.appendSkipEmpty("collectionFormat", a.collectionFormat())
+			.appendSkipEmpty("pattern", a.pattern())
+			.appendSkipEmpty("$ref", a.$ref())
+			.appendSkipEmpty("maximum", a.maximum())
+			.appendSkipEmpty("minimum", a.minimum())
+			.appendSkipEmpty("multipleOf", a.multipleOf())
+			.appendSkipMinusOne("maxLength", a.maxLength())
+			.appendSkipMinusOne("minLength", a.minLength())
+			.appendSkipMinusOne("maxItems", a.maxItems())
+			.appendSkipMinusOne("minItems", a.minItems())
+			.appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum())
+			.appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum())
+			.appendSkipFalse("uniqueItems", a.uniqueItems())
+			.appendSkipEmpty("default", joinnl(a._default()))
+			.appendSkipEmpty("enum", joinnl(a._enum()))
+			.appendSkipEmpty("items", joinnl(a.items()))
+			;
 	}	
 
 	/**
@@ -210,13 +247,13 @@ public class AnnotationUtils {
 			.appendSkipEmpty("maximum", a.maximum())
 			.appendSkipEmpty("minimum", a.minimum())
 			.appendSkipEmpty("multipleOf", a.multipleOf())
-			.appendSkipEmpty("maxLength", a.maxLength())
-			.appendSkipEmpty("minLength", a.minLength())
-			.appendSkipEmpty("maxItems", a.maxItems())
-			.appendSkipEmpty("minItems", a.minItems())
-			.appendSkipEmpty("exclusiveMaximum", a.exclusiveMaximum())
-			.appendSkipEmpty("exclusiveMinimum", a.exclusiveMinimum())
-			.appendSkipEmpty("uniqueItems", a.uniqueItems())
+			.appendSkipMinusOne("maxLength", a.maxLength())
+			.appendSkipMinusOne("minLength", a.minLength())
+			.appendSkipMinusOne("maxItems", a.maxItems())
+			.appendSkipMinusOne("minItems", a.minItems())
+			.appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum())
+			.appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum())
+			.appendSkipFalse("uniqueItems", a.uniqueItems())
 			.appendSkipEmpty("default", joinnl(a._default()))
 			.appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items()))
 			.appendSkipEmpty("default", joinnl(a._default()))
@@ -255,17 +292,17 @@ public class AnnotationUtils {
 			.appendSkipEmpty("_value", joinnl(a.api()))
 			.appendSkipEmpty("description", joinnl(a.description()))
 			.appendSkipEmpty("type", a.type())
+			.appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items()))
 			.appendSkipEmpty("format", a.format())
 			.appendSkipEmpty("pattern", a.pattern())
 			.appendSkipEmpty("collectionFormat", a.collectionFormat())
 			.appendSkipEmpty("maximum", a.maximum())
 			.appendSkipEmpty("minimum", a.minimum())
 			.appendSkipEmpty("multipleOf", a.multipleOf())
-			.appendSkipEmpty("maxLength", a.maxLength())
-			.appendSkipEmpty("minLength", a.minLength())
-			.appendSkipEmpty("exclusiveMaximum", a.exclusiveMaximum())
-			.appendSkipEmpty("exclusiveMinimum", a.exclusiveMinimum())
-			.appendSkipEmpty("schema", merge(om.getObjectMap("schema"), a.schema()))
+			.appendSkipMinusOne("maxLength", a.maxLength())
+			.appendSkipMinusOne("minLength", a.minLength())
+			.appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum())
+			.appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum())
 			.appendSkipEmpty("enum", joinnl(a._enum()))
 			.appendSkipEmpty("example", joinnl(a.example()));
 	}
@@ -284,7 +321,7 @@ public class AnnotationUtils {
 		return om
 			.appendSkipEmpty("_value", joinnl(a.api()))
 			.appendSkipEmpty("description", joinnl(a.description()))
-			.appendSkipEmpty("required", a.required())
+			.appendSkipFalse("required", a.required())
 			.appendSkipEmpty("type", a.type())
 			.appendSkipEmpty("format", a.format())
 			.appendSkipEmpty("pattern", a.pattern())
@@ -292,15 +329,14 @@ public class AnnotationUtils {
 			.appendSkipEmpty("maximum", a.maximum())
 			.appendSkipEmpty("minimum", a.minimum())
 			.appendSkipEmpty("multipleOf", a.multipleOf())
-			.appendSkipEmpty("maxLength", a.maxLength())
-			.appendSkipEmpty("minLength", a.minLength())
-			.appendSkipEmpty("maxItems", a.maxItems())
-			.appendSkipEmpty("minItems", a.minItems())
-			.appendSkipEmpty("allowEmptyValue", a.allowEmptyValue())
-			.appendSkipEmpty("exclusiveMaximum", a.exclusiveMaximum())
-			.appendSkipEmpty("exclusiveMinimum", a.exclusiveMinimum())
-			.appendSkipEmpty("uniqueItems", a.uniqueItems())
-			.appendSkipEmpty("schema", merge(om.getObjectMap("schema"), a.schema()))
+			.appendSkipMinusOne("maxLength", a.maxLength())
+			.appendSkipMinusOne("minLength", a.minLength())
+			.appendSkipMinusOne("maxItems", a.maxItems())
+			.appendSkipMinusOne("minItems", a.minItems())
+			.appendSkipFalse("allowEmptyValue", a.allowEmptyValue())
+			.appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum())
+			.appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum())
+			.appendSkipFalse("uniqueItems", a.uniqueItems())
 			.appendSkipEmpty("default", joinnl(a._default()))
 			.appendSkipEmpty("enum", joinnl(a._enum()))
 			.appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items()))
@@ -321,7 +357,7 @@ public class AnnotationUtils {
 		return om
 			.appendSkipEmpty("_value", joinnl(a.api()))
 			.appendSkipEmpty("description", joinnl(a.description()))
-			.appendSkipEmpty("required", a.required())
+			.appendSkipFalse("required", a.required())
 			.appendSkipEmpty("type", a.type())
 			.appendSkipEmpty("format", a.format())
 			.appendSkipEmpty("pattern", a.pattern())
@@ -329,14 +365,13 @@ public class AnnotationUtils {
 			.appendSkipEmpty("maximum", a.maximum())
 			.appendSkipEmpty("minimum", a.minimum())
 			.appendSkipEmpty("multipleOf", a.multipleOf())
-			.appendSkipEmpty("maxLength", a.maxLength())
-			.appendSkipEmpty("minLength", a.minLength())
-			.appendSkipEmpty("maxItems", a.maxItems())
-			.appendSkipEmpty("minItems", a.minItems())
-			.appendSkipEmpty("exclusiveMaximum", a.exclusiveMaximum())
-			.appendSkipEmpty("exclusiveMinimum", a.exclusiveMinimum())
-			.appendSkipEmpty("uniqueItems", a.uniqueItems())
-			.appendSkipEmpty("schema", merge(om.getObjectMap("schema"), a.schema()))
+			.appendSkipMinusOne("maxLength", a.maxLength())
+			.appendSkipMinusOne("minLength", a.minLength())
+			.appendSkipMinusOne("maxItems", a.maxItems())
+			.appendSkipMinusOne("minItems", a.minItems())
+			.appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum())
+			.appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum())
+			.appendSkipFalse("uniqueItems", a.uniqueItems())
 			.appendSkipEmpty("default", joinnl(a._default()))
 			.appendSkipEmpty("enum", joinnl(a._enum()))
 			.appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items()))
@@ -357,7 +392,7 @@ public class AnnotationUtils {
 		return om
 			.appendSkipEmpty("_value", joinnl(a.api()))
 			.appendSkipEmpty("description", joinnl(a.description()))
-			.appendSkipEmpty("required", a.required())
+			.appendSkipFalse("required", a.required())
 			.appendSkipEmpty("type", a.type())
 			.appendSkipEmpty("format", a.format())
 			.appendSkipEmpty("pattern", a.pattern())
@@ -365,15 +400,14 @@ public class AnnotationUtils {
 			.appendSkipEmpty("maximum", a.maximum())
 			.appendSkipEmpty("minimum", a.minimum())
 			.appendSkipEmpty("multipleOf", a.multipleOf())
-			.appendSkipEmpty("maxLength", a.maxLength())
-			.appendSkipEmpty("minLength", a.minLength())
-			.appendSkipEmpty("maxItems", a.maxItems())
-			.appendSkipEmpty("minItems", a.minItems())
-			.appendSkipEmpty("allowEmptyValue", a.allowEmptyValue())
-			.appendSkipEmpty("exclusiveMaximum", a.exclusiveMaximum())
-			.appendSkipEmpty("exclusiveMinimum", a.exclusiveMinimum())
-			.appendSkipEmpty("uniqueItems", a.uniqueItems())
-			.appendSkipEmpty("schema", merge(om.getObjectMap("schema"), a.schema()))
+			.appendSkipMinusOne("maxLength", a.maxLength())
+			.appendSkipMinusOne("minLength", a.minLength())
+			.appendSkipMinusOne("maxItems", a.maxItems())
+			.appendSkipMinusOne("minItems", a.minItems())
+			.appendSkipFalse("allowEmptyValue", a.allowEmptyValue())
+			.appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum())
+			.appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum())
+			.appendSkipFalse("uniqueItems", a.uniqueItems())
 			.appendSkipEmpty("default", joinnl(a._default()))
 			.appendSkipEmpty("enum", joinnl(a._enum()))
 			.appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items()))
@@ -395,11 +429,9 @@ public class AnnotationUtils {
 			return true;
 		return 
 			empty(a.description(), a._default(), a.example(), a.api())
-			&& empty(
-				a.name(), a.value(), a.required(), a.type(), a.format(), a.pattern(), a.collectionFormat(), a.maximum(), a.minimum(), a.multipleOf(), a.maxLength(), a.minLength(),
-				a.maxItems(), a.minItems(), a.allowEmptyValue(), a.exclusiveMaximum(), a.exclusiveMinimum(), a.uniqueItems()
-			)
-			&& empty(a.schema())
+			&& empty(a.name(), a.value(), a.type(), a.format(), a.pattern(), a.collectionFormat(), a.maximum(), a.minimum(), a.multipleOf())
+			&& empty(a.allowEmptyValue(), a.exclusiveMaximum(), a.exclusiveMinimum(), a.required(), a.uniqueItems())
+			&& empty(a.maxLength(), a.minLength(), a.maxItems(), a.minItems())
 			&& empty(a.items());
 	}
 
@@ -414,11 +446,9 @@ public class AnnotationUtils {
 			return true;
 		return 
 			empty(a.description(), a._default(), a._enum(), a.example(), a.api())
-			&& empty(
-				a.name(), a.value(), a.required(), a.type(), a.format(), a.pattern(), a.collectionFormat(), a.maximum(), a.minimum(), a.multipleOf(), a.maxLength(), 
-				a.minLength(), a.maxItems(), a.minItems(), a.exclusiveMaximum(), a.exclusiveMinimum(), a.uniqueItems()
-			)
-			&& empty(a.schema())
+			&& empty(a.name(), a.value(), a.type(), a.format(), a.pattern(), a.collectionFormat(), a.maximum(), a.minimum(), a.multipleOf())
+			&& empty(a.exclusiveMaximum(), a.exclusiveMinimum(), a.required(), a.uniqueItems())
+			&& empty(a.maxLength(), a.minLength(), a.maxItems(), a.minItems())
 			&& empty(a.items());
 	}
 
@@ -433,11 +463,9 @@ public class AnnotationUtils {
 			return true;
 		return 
 			empty(a.description(), a._default(), a._enum(), a.example(), a.api())
-			&& empty(
-				a.name(), a.value(), a.required(), a.type(), a.format(), a.pattern(), a.collectionFormat(), a.maximum(), a.minimum(), a.multipleOf(), a.maxLength(), 
-				a.minLength(), a.maxItems(), a.minItems(), a.allowEmptyValue(), a.exclusiveMaximum(), a.exclusiveMinimum(), a.uniqueItems()
-			)
-			&& empty(a.schema())
+			&& empty(a.name(), a.value(), a.type(), a.format(), a.pattern(), a.collectionFormat(), a.maximum(), a.minimum(), a.multipleOf())
+			&& empty(a.allowEmptyValue(), a.exclusiveMaximum(), a.exclusiveMinimum(), a.required(), a.uniqueItems())
+			&& empty(a.maxLength(), a.minLength(), a.maxItems(), a.minItems())
 			&& empty(a.items());
 	}
 	
@@ -468,10 +496,9 @@ public class AnnotationUtils {
 			return true;
 		return
 			empty(a.description(), a._default(), a._enum(), a.example(), a.api())
-			&& empty(
-				a.name(), a.value(), a.type(), a.format(), a.collectionFormat(), a.$ref(), a.maximum(), a.minimum(), a.multipleOf(), 
-				a.maxLength(), a.minLength(), a.exclusiveMaximum(), a.exclusiveMinimum(), a.uniqueItems()
-			)
+			&& empty(a.name(), a.value(), a.type(), a.format(), a.collectionFormat(), a.$ref(), a.maximum(), a.minimum(), a.multipleOf())
+			&& empty(a.exclusiveMaximum(), a.exclusiveMinimum(), a.uniqueItems())
+			&& empty(a.maxLength(), a.minLength(), a.maxItems(), a.minItems())
 			&& empty(a.items());
 	}
 
@@ -498,15 +525,10 @@ public class AnnotationUtils {
 		if (a == null)
 			return true;
 		return 
-			empty(
-				a.value(), a.description(), a._default(), a._enum(), a.allOf(), a.properties(), a.additionalProperties(), a.xml(), a.example(), a.examples()
-			)
-			&& empty(
-				a.$ref(), a.format(), a.title(), a.multipleOf(), a.maximum(), a.exclusiveMaximum(), a.minimum(), a.exclusiveMinimum(), a.maxLength(), 
-				a.minLength(), a.pattern(), a.maxItems(), a.minItems(), a.uniqueItems(), a.maxProperties(), a.minProperties(), a.required(),
-				a.type(), a.discriminator(), a.readOnly()
-			)
-			&& ! a.ignore()
+			empty(a.value(), a.description(), a._default(), a._enum(), a.allOf(), a.properties(), a.additionalProperties(), a.xml(), a.example(), a.examples())
+			&& empty(a.$ref(), a.format(), a.title(), a.multipleOf(), a.maximum(), a.minimum(), a.pattern(), a.maxProperties(), a.minProperties(), a.type(), a.discriminator())
+			&& empty(a.ignore(), a.exclusiveMaximum(), a.exclusiveMinimum(), a.readOnly(), a.required(), a.uniqueItems())
+			&& empty(a.maxLength(), a.minLength(), a.maxItems(), a.minItems())
 			&& empty(a.items())
 			&& empty(a.externalDocs());
 	}
@@ -579,10 +601,26 @@ public class AnnotationUtils {
 			return true;
 		return
 			empty(a.value(), a._default(), a._enum())
-			&& empty(
-				a.type(), a.format(), a.collectionFormat(), a.pattern(), a.$ref(), a.maximum(), a.minimum(), a.multipleOf(), 
-				a.maxLength(), a.minLength(), a.maxItems(), a.minItems(), a.exclusiveMaximum(), a.exclusiveMinimum(), a.uniqueItems()
-			);
+			&& empty(a.type(), a.format(), a.collectionFormat(), a.pattern(), a.$ref(), a.maximum(), a.minimum(), a.multipleOf())
+			&& empty(a.exclusiveMaximum(), a.exclusiveMinimum(), a.uniqueItems())
+			&& empty(a.maxLength(), a.minLength(), a.maxItems(), a.minItems())
... 2536 lines suppressed ...