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/08/02 01:04:50 UTC

[juneau] branch master updated: BasicRestInfoProvider refactor.

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 6434926  BasicRestInfoProvider refactor.
6434926 is described below

commit 64349267f2df80cdc48ec20e69ea4f98f79ef673
Author: JamesBognar <ja...@apache.org>
AuthorDate: Wed Aug 1 21:04:36 2018 -0400

    BasicRestInfoProvider refactor.
---
 .../apache/juneau/dto/swagger/ParameterInfo.java   |  10 +-
 .../apache/juneau/internal/ReflectionUtils.java    |  17 ++
 .../apache/juneau/rest/BasicRestInfoProvider.java  | 245 ++++++++++++++++++---
 .../juneau/rest/BasicRestInfoProviderTest.java     |  48 ++--
 .../juneau/rest/annotation/BodyAnnotationTest.java |  36 +--
 .../rest/annotation/FormDataAnnotationTest.java    |   4 +-
 .../rest/annotation/HeaderAnnotationTest.java      |   2 +-
 .../juneau/rest/annotation/PathAnnotationTest.java |  10 +-
 .../rest/annotation/QueryAnnotationTest.java       |   2 +-
 .../rest/annotation/ResponseAnnotationTest.java    |  22 +-
 .../rest/BasicRestInfoProviderTest_swagger.json    |  10 +-
 11 files changed, 303 insertions(+), 103 deletions(-)

diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ParameterInfo.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ParameterInfo.java
index 861527d..d94957b 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ParameterInfo.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ParameterInfo.java
@@ -124,7 +124,7 @@ public class ParameterInfo extends SwaggerElement {
 	private Items items;
 	private Object _default;
 	private List<Object> _enum;
-	private Object example;
+	private String example;
 	private Map<String,String> examples;
 
 	/**
@@ -242,7 +242,7 @@ public class ParameterInfo extends SwaggerElement {
 			if (p._enum != null)
 				_enum = p._enum;
 			if (p.example != null)
-				example = p.examples;
+				example = p.example;
 			if (p.examples != null)
 				examples = p.examples;
 		}
@@ -1428,7 +1428,7 @@ public class ParameterInfo extends SwaggerElement {
 	 * @return The property value, or <jk>null</jk> if it is not set.
 	 */
 	@BeanProperty("x-example")
-	public Object getExample() {
+	public String getExample() {
 		return example;
 	}
 
@@ -1441,7 +1441,7 @@ public class ParameterInfo extends SwaggerElement {
 	 * @return This object (for method chaining).
 	 */
 	@BeanProperty("x-example")
-	public ParameterInfo setExample(Object value) {
+	public ParameterInfo setExample(String value) {
 		example = value;
 		return this;
 	}
@@ -1453,7 +1453,7 @@ public class ParameterInfo extends SwaggerElement {
 	 * @return This object (for method chaining).
 	 */
 	public ParameterInfo example(Object value) {
-		example = value;
+		example = StringUtils.asString(value);
 		return this;
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ReflectionUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ReflectionUtils.java
index e04b2cc..6f6cdc0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ReflectionUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ReflectionUtils.java
@@ -107,6 +107,23 @@ public final class ReflectionUtils {
 	}
 
 	/**
+	 * Returns all annotations defined on the specified parameter and parameter type.
+	 *
+	 * <p>
+	 * Annotations are ordered parameter superclasses first, then class, then parameter.
+	 *
+	 * @param a The annotation to look for.
+	 * @param m The method containing the parameter.
+	 * @param index The parameter index.
+	 * @return All instances of the annotation with the
+	 */
+	public static <T extends Annotation> List<T> getAnnotationsParentFirst(Class<T> a, Method m, int index) {
+		List<T> l = getAnnotations(a, m, index);
+		Collections.reverse(l);
+		return l;
+	}
+
+	/**
 	 * Returns the specified annotation if it exists on the specified method or return type class.
 	 *
 	 * @param a The annotation to check for.
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 fd69397..d3c7a08 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
@@ -28,6 +28,7 @@ import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.http.*;
 import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.http.annotation.Contact;
+import org.apache.juneau.http.annotation.Items;
 import org.apache.juneau.http.annotation.License;
 import org.apache.juneau.http.annotation.Tag;
 import org.apache.juneau.httppart.*;
@@ -408,8 +409,12 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 						param.append("name", mp.name);
 
 					ObjectMap pi = null;
-					if (in == BODY)
-						pi = HttpPartSchema.create(Body.class, mp.method, mp.index).getApi();
+					if (in == BODY) {
+						for (Body b : getAnnotationsParentFirst(Body.class, mp.method, mp.index))
+							merge(param, b, vr, "ParameterInfo on class {0} method {1}", c, m);
+						if (! param.containsKey("schema"))
+							param.put("schema", getSchema(req, param.getObjectMap("schema", true), js, mp.getType()));
+					}
 					else if (in == QUERY)
 						pi = HttpPartSchema.create(Query.class, mp.method, mp.index).getApi();
 					else if (in == FORM_DATA)
@@ -424,15 +429,15 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 					pi = resolve(vr, pi, "ParameterInfo on class {0} method {1}", c, m);
 
 					// Common to all
-					param.appendSkipEmpty("description", resolve(vr, pi.getString("description")));
-					param.appendSkipEmpty("required", resolve(vr, pi.getString("required")));
 
 					if (in == BODY) {
-						param.put("schema", getSchema(req, param.getObjectMap("schema", true), js, mp.getType()));
-						param.appendSkipEmpty("schema", parseMap(vr, pi.get("schema"), "ParameterInfo/schema on class {0} method {1}", c, m));
-						param.appendSkipEmpty("x-example", parseAnything(vr, pi.getString("example"), "ParameterInfo/example on class {0} method {1}", c, m));
-						param.appendSkipEmpty("x-examples", parseMap(vr, pi.get("examples"), "ParameterInfo/examples on class {0} method {1}", c, m));
+//						param.put("schema", getSchema(req, param.getObjectMap("schema", true), js, mp.getType()));
+//						param.appendSkipEmpty("schema", parseMap(vr, pi.get("schema"), "ParameterInfo/schema on class {0} method {1}", c, m));
+//						param.appendSkipEmpty("x-example", parseAnything(vr, pi.getString("example"), "ParameterInfo/example on class {0} method {1}", c, m));
+//						param.appendSkipEmpty("x-examples", parseMap(vr, pi.get("examples"), "ParameterInfo/examples on class {0} method {1}", c, m));
 					} else {
+						param.appendSkipEmpty("description", resolve(vr, pi.getString("description")));
+						param.appendSkipEmpty("required", resolve(vr, pi.getString("required")));
 						param.appendSkipEmpty("type", resolve(vr, pi.getString("type")));
 						param.appendSkipEmpty("format", resolve(vr, pi.getString("format")));
 						param.appendSkipEmpty("pattern", resolve(vr, pi.getString("pattern")));
@@ -451,7 +456,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 						param.appendSkipEmpty("schema", parseMap(vr, pi.get("schema"), "ParameterInfo/schema on class {0} method {1}", c, m));
 						param.appendSkipEmpty("default", parseAnything(vr, pi.getString("default"), "ParameterInfo/default on class {0} method {1}", c, m));
 						param.appendSkipEmpty("enum", parseListOrCdl(vr, pi.getString("enum"), "ParameterInfo/enum on class {0} method {1}", c, m));
-						param.appendSkipEmpty("x-example", parseAnything(vr, pi.getString("example"), "ParameterInfo/example on class {0} method {1}", c, m));
+						param.appendSkipEmpty("x-example", resolve(vr, pi.getString("example")));
 						param.appendSkipEmpty("x-examples", parseMap(vr, pi.get("examples"), "ParameterInfo/examples on class {0} method {1}", c, m));
 						param.appendSkipEmpty("items", parseMap(vr, pi.get("items"), "ParameterInfo/items on class {0} method {1}", c, m));
 
@@ -490,7 +495,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 
 						if (api != null) {
 							om.appendSkipEmpty("description", resolve(vr, api.getString("description")));
-							om.appendSkipEmpty("x-example", parseAnything(vr, api.getString("example"), "RestMethodThrown/example on class {0} method {1}", c, m));
+							om.appendSkipEmpty("x-example", resolve(vr, api.getString("example")));
 							om.appendSkipEmpty("examples", api.getObjectMap("examples"));
 							om.appendSkipEmpty("schema", api.getObjectMap("schema"));
 							if (api.containsKey("headers"))
@@ -498,7 +503,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 									headers.put(e.getKey(), e.getValue());
 						}
 						om.appendSkipEmpty("description", resolve(vr, r.description()));
-						om.appendSkipEmpty("x-example", parseAnything(vr, r.example(), "RestMethodThrown/example on class {0} method {1}", c, m));
+						om.appendSkipEmpty("x-example", resolve(vr, r.example()));
 						om.appendSkipEmpty("examples", parseMap(vr, r.examples(), "RestMethodThrown/examples on class {0} method {1}", c, m));
 						om.appendSkipEmpty("schema", resolve(vr, HttpPartSchema.create(r.schema()).getApi()));
 						for (ResponseHeader h : r.headers()) {
@@ -525,7 +530,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 
 					if (api != null) {
 						om.appendSkipEmpty("description", api.getString("description"));
-						om.appendSkipEmpty("x-example", parseAnything(vr, api.getString("example"), "RestMethodReturn/example on class {0} method {1}", c, m));
+						om.appendSkipEmpty("x-example", resolve(vr, api.getString("example")));
 						om.appendSkipEmpty("examples", api.getObjectMap("examples"));
 						om.appendSkipEmpty("schema", api.getObjectMap("schema"));
 						if (api.containsKey("headers"))
@@ -533,7 +538,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 								headers.put(e.getKey(), e.getValue());
 					}
 					om.appendSkipEmpty("description", resolve(vr, r.description()));
-					om.appendSkipEmpty("x-example", parseAnything(vr, r.example(), "RestMethodReturn/example on class {0} method {1}", c, m));
+					om.appendSkipEmpty("x-example", resolve(vr, r.example()));
 					om.appendSkipEmpty("examples", parseMap(vr, r.examples(), "RestMethodReturn/examples on class {0} method {1}", c, m));
 					om.appendSkipEmpty("schema", resolve(vr, HttpPartSchema.create(r.schema()).getApi()));
 					for (ResponseHeader h : r.headers()) {
@@ -560,14 +565,14 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 
 				if (api != null) {
 					om.appendSkipEmpty("description", api.getString("description"));
-					om.appendSkipEmpty("x-example", parseAnything(vr, api.getString("example"), "RestMethodReturn/example on class {0} method {1}", c, m));
+					om.appendSkipEmpty("x-example", resolve(vr, api.getString("example")));
 					om.appendSkipEmpty("examples", api.getObjectMap("examples"));
 					om.appendSkipEmpty("schema", api.getObjectMap("schema"));
 					if (api.containsKey("headers"))
 						for (Map.Entry<String,Object> e : api.getObjectMap("headers").entrySet())
 							headers.put(e.getKey(), e.getValue());
 				}
-				om.appendSkipEmpty("x-example", parseAnything(vr, r.example(), "RestMethodReturn/example on class {0} method {1}", c, m));
+				om.appendSkipEmpty("x-example", resolve(vr, r.example()));
 				om.appendSkipEmpty("examples", parseMap(vr, r.examples(), "RestMethodReturn/examples on class {0} method {1}", c, m));
 				om.appendSkipEmpty("schema", resolve(vr, HttpPartSchema.create(r.schema()).getApi()));
 
@@ -614,7 +619,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 						header.appendSkipEmpty("uniqueItems", resolve(vr, pi2.getString("uniqueItems")));
 						header.appendSkipEmpty("default", parseAnything(vr, pi2.getString("default"), "@ResponseHeader/default on class {0} method {1}", c, m));
 						header.appendSkipEmpty("enum", parseListOrCdl(vr, pi2.getString("enum"), "@ResponseHeader/enum on class {0} method {1}", c, m));
-						header.appendSkipEmpty("x-example", parseAnything(vr, pi2.getString("example"), "@ResponseHeader/example on class {0} method {1}", c, m));
+						header.appendSkipEmpty("x-example", resolve(vr, pi2.getString("example")));
 						header.appendSkipEmpty("examples", parseMap(vr, pi2.get("examples"), "@ResponseHeader/examples on class {0} method {1}", c, m));
 						header.appendSkipEmpty("items", parseMap(vr, pi2.get("items"), "@ResponseHeader/items on class {0} method {1}", c, m));
 					}
@@ -631,7 +636,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 						response.appendSkipEmpty("description", resolve(vr, pi2.getString("description")));
 						response.appendSkipEmpty("schema", parseMap(vr, pi2.get("schema"), "@Response/schema on class {0} method {1}", c, m));
 						response.appendSkipEmpty("headers", parseMap(vr, pi2.get("headers"), "@Response/headers on class {0} method {1}", c, m));
-						response.appendSkipEmpty("x-example", parseAnything(vr, pi2.getString("example"), "@Response/example on class {0} method {1}", c, m));
+						response.appendSkipEmpty("x-example", resolve(vr, pi2.getString("example")));
 						response.appendSkipEmpty("examples", parseMap(vr, pi2.get("examples"), "@Response/examples on class {0} method {1}", c, m));
 
 						Type type = mp.getType();
@@ -654,7 +659,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 						ObjectMap response = responses.getObjectMap(code, true);
 
 						response.appendSkipEmpty("schema", parseMap(vr, pi2.get("schema"), "@ResponseBody/schema on class {0} method {1}", c, m));
-						response.appendSkipEmpty("x-example", parseAnything(vr, pi2.getString("example"), "@ResponseBody/example on class {0} method {1}", c, m));
+						response.appendSkipEmpty("x-example", resolve(vr, pi2.getString("example")));
 						response.appendSkipEmpty("examples", parseMap(vr, pi2.get("examples"), "@ResponseBody/examples on class {0} method {1}", c, m));
 
 						Type type = mp.getType();
@@ -719,6 +724,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 
 		try {
 			String swaggerJson = omSwagger.toString(SimpleJsonSerializer.DEFAULT_READABLE);
+//			System.err.println(swaggerJson);
 			swagger = jp.parse(swaggerJson, Swagger.class);
 		} catch (Exception e) {
 			throw new RestServletException("Error detected in swagger.").initCause(e);
@@ -780,12 +786,26 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 		return ol2;
 	}
 
-	private String resolve(VarResolverSession vs, String[] s) {
-		return resolve(vs, joinnl(s));
+	private static String resolve(VarResolverSession vs, String[] ss) {
+		if (ss.length == 0)
+			return null;
+		return resolve(vs, joinnl(ss));
+	}
+
+	private static String resolve(VarResolverSession vs, String s) {
+		if (s == null)
+			return null;
+		return vs.resolve(s.trim());
 	}
 
-	private String resolve(VarResolverSession vs, String s) {
-		return vs.resolve(s);
+	private ObjectMap parseMap(VarResolverSession vs, String[] o, String location, Object...args) throws ParseException {
+		if (o.length == 0)
+			return ObjectMap.EMPTY_MAP;
+		try {
+			return parseMap(vs, o);
+		} catch (ParseException e) {
+			throw new SwaggerException(e, "Malformed swagger JSON object encountered in " + location + ".", args);
+		}
 	}
 
 	private ObjectMap parseMap(VarResolverSession vs, Object o, String location, Object...args) throws ParseException {
@@ -796,7 +816,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 		}
 	}
 
-	private ObjectMap parseMap(VarResolverSession vs, Object o) throws ParseException {
+	private static ObjectMap parseMap(VarResolverSession vs, Object o) throws ParseException {
 		if (o == null)
 			return null;
 		if (o instanceof String[])
@@ -980,22 +1000,22 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 
 	private void addXExamples(RestRequest req, RestJavaMethod sm, ObjectMap piri, String in, JsonSchemaSerializerSession js, Type type) throws Exception {
 
-		Object example = piri.get("x-example");
+		String sex = piri.getString("x-example");
 
-		if (example == null) {
+		if (sex == null) {
 			ObjectMap schema = resolve(js, piri.getObjectMap("schema"));
 			if (schema != null)
-				example = schema.getWithDefault("example", schema.get("x-example"));
+				sex = schema.getString("example", schema.getString("x-example"));
 		}
 
-		if (example == null)
+		if (isEmpty(sex))
 			return;
 
 		boolean isOk = "ok".equals(in), isBody = "body".equals(in);
 
-		String sex = example.toString();
+		Object example = null;
 		if (isJson(sex)) {
-			example = JsonParser.DEFAULT.parse(JsonSerializer.DEFAULT.serialize(example), type);
+			example = JsonParser.DEFAULT.parse(sex, type);
 		} else {
 			ClassMeta<?> cm = js.getClassMeta(type);
 			if (cm.hasStringTransform()) {
@@ -1364,4 +1384,171 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 		}
 		return null;
 	}
+
+	private static ObjectMap newMap(ObjectMap om) {
+		if (om == null)
+			return new ObjectMap();
+		return om.modifiable();
+	}
+
+	private static ObjectMap merge(ObjectMap om, Body a, VarResolverSession vr, String location, Object...args) throws SwaggerException {
+		try {
+			if (empty(a))
+				return om;
+			om = newMap(om);
+			if (a.value().length > 0)
+				om.putAll(parseMap(vr, a.value()));
+			if (a.api().length > 0)
+				om.putAll(parseMap(vr, a.api()));
+			return om
+				.appendSkipEmpty("description", resolve(vr, a.description()))
+				.appendSkipEmpty("x-example", resolve(vr, a.example()))
+				.appendSkipEmpty("x-examples", parseMap(vr, a.examples()))
+				.appendSkipFalse("required", a.required())
+				.appendSkipEmpty("schema", merge(om.getObjectMap("schema"), a.schema(), vr, location, args))
+			;
+		} catch (ParseException e) {
+			throw new SwaggerException(e, "Malformed swagger JSON object encountered in " + location + ".", args);
+		}
+	}
+
+	private static ObjectMap merge(ObjectMap om, Schema a, VarResolverSession vr, String location, Object...args) throws SwaggerException {
+		try {
+			if (empty(a))
+				return om;
+			om = newMap(om);
+			if (a.value().length > 0)
+				om.putAll(parseMap(vr, a.value()));
+			return om
+				.appendSkipEmpty("additionalProperties", toObjectMap(a.additionalProperties(), vr))
+				.appendSkipEmpty("allOf", joinnl(a.allOf()))
+				.appendSkipEmpty("collectionFormat", a.collectionFormat())
+				.appendSkipEmpty("default", joinnl(a._default()))
+				.appendSkipEmpty("discriminator", a.discriminator())
+				.appendSkipEmpty("description", joinnl(a.description()))
+				.appendSkipEmpty("enum", toSet(a._enum(), vr))
+				.appendSkipEmpty("example", joinnl(a.example()))
+				.appendSkipEmpty("examples", joinnl(a.examples()))
+				.appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum())
+				.appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum())
+				.appendSkipEmpty("externalDocs", merge(om.getObjectMap("externalDocs"), a.externalDocs(), vr))
+				.appendSkipEmpty("format", a.format())
+				.appendSkipEmpty("ignore", a.ignore() ? "true" : null)
+				.appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items(), vr))
+				.appendSkipEmpty("maximum", a.maximum())
+				.appendSkipMinusOne("maxItems", a.maxItems())
+				.appendSkipMinusOne("maxLength", a.maxLength())
+				.appendSkipMinusOne("maxProperties", a.maxProperties())
+				.appendSkipEmpty("minimum", a.minimum())
+				.appendSkipMinusOne("minItems", a.minItems())
+				.appendSkipMinusOne("minLength", a.minLength())
+				.appendSkipMinusOne("minProperties", a.minProperties())
+				.appendSkipEmpty("multipleOf", a.multipleOf())
+				.appendSkipEmpty("pattern", a.pattern())
+				.appendSkipEmpty("properties", toObjectMap(a.properties(), vr))
+				.appendSkipFalse("readOnly", a.readOnly())
+				.appendSkipFalse("required", a.required())
+				.appendSkipEmpty("title", a.title())
+				.appendSkipEmpty("type", a.type())
+				.appendSkipFalse("uniqueItems", a.uniqueItems())
+				.appendSkipEmpty("xml", joinnl(a.xml()))
+				.appendSkipEmpty("$ref", a.$ref())
+			;
+		} catch (ParseException e) {
+			throw new SwaggerException(e, "Malformed swagger JSON object encountered in " + location + ".", args);
+		}
+	}
+
+	private static ObjectMap merge(ObjectMap om, ExternalDocs a, VarResolverSession vr) throws ParseException {
+		if (empty(a))
+			return om;
+		om = newMap(om);
+		if (a.value().length > 0)
+			om.putAll(parseMap(vr, a.value()));
+		return om
+			.appendSkipEmpty("description", resolve(vr, a.description()))
+			.appendSkipEmpty("url", a.url())
+		;
+	}
+
+	private static ObjectMap merge(ObjectMap om, Items a, VarResolverSession vr) throws ParseException {
+		if (empty(a))
+			return om;
+		om = newMap(om);
+		if (a.value().length > 0)
+			om.putAll(parseMap(vr, a.value()));
+		return om
+			.appendSkipEmpty("collectionFormat", a.collectionFormat())
+			.appendSkipEmpty("default", joinnl(a._default()))
+			.appendSkipEmpty("enum", toSet(a._enum(), vr))
+			.appendSkipEmpty("format", a.format())
+			.appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum())
+			.appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum())
+			.appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items(), vr))
+			.appendSkipEmpty("maximum", a.maximum())
+			.appendSkipMinusOne("maxItems", a.maxItems())
+			.appendSkipMinusOne("maxLength", a.maxLength())
+			.appendSkipEmpty("minimum", a.minimum())
+			.appendSkipMinusOne("minItems", a.minItems())
+			.appendSkipMinusOne("minLength", a.minLength())
+			.appendSkipEmpty("multipleOf", a.multipleOf())
+			.appendSkipEmpty("pattern", a.pattern())
+			.appendSkipFalse("uniqueItems", a.uniqueItems())
+			.appendSkipEmpty("type", a.type())
+			.appendSkipEmpty("$ref", a.$ref())
+		;
+	}
+
+	private static ObjectMap merge(ObjectMap om, SubItems a, VarResolverSession vr) throws ParseException {
+		if (empty(a))
+			return om;
+		om = newMap(om);
+		if (a.value().length > 0)
+			om.putAll(parseMap(vr, a.value()));
+		return om
+			.appendSkipEmpty("collectionFormat", a.collectionFormat())
+			.appendSkipEmpty("default", joinnl(a._default()))
+			.appendSkipEmpty("enum", toSet(a._enum(), vr))
+			.appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum())
+			.appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum())
+			.appendSkipEmpty("format", a.format())
+			.appendSkipEmpty("items", toObjectMap(a.items(), vr))
+			.appendSkipEmpty("maximum", a.maximum())
+			.appendSkipMinusOne("maxItems", a.maxItems())
+			.appendSkipMinusOne("maxLength", a.maxLength())
+			.appendSkipEmpty("minimum", a.minimum())
+			.appendSkipMinusOne("minItems", a.minItems())
+			.appendSkipMinusOne("minLength", a.minLength())
+			.appendSkipEmpty("multipleOf", a.multipleOf())
+			.appendSkipEmpty("pattern", a.pattern())
+			.appendSkipEmpty("type", a.type())
+			.appendSkipFalse("uniqueItems", a.uniqueItems())
+			.appendSkipEmpty("$ref", a.$ref())
+		;
+	}
+
+	private static ObjectMap toObjectMap(String[] ss, VarResolverSession vr) throws ParseException {
+		if (ss.length == 0)
+			return null;
+		String s = joinnl(ss);
+		if (s.isEmpty())
+			return null;
+		if (! isObjectMap(s, true))
+			s = "{" + s + "}";
+		s = vr.resolve(s);
+		return new ObjectMap(s);
+	}
+
+	private static Set<String> toSet(String[] ss, VarResolverSession vr) throws ParseException {
+		if (ss.length == 0)
+			return null;
+		String s = joinnl(ss);
+		if (s.isEmpty())
+			return null;
+		s = vr.resolve(s);
+		Set<String> set = new ASet<>();
+		for (Object o : StringUtils.parseListOrCdl(s))
+			set.add(o.toString());
+		return set;
+	}
 }
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
index e5121a4..618bc6c 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
@@ -1598,10 +1598,10 @@ public class BasicRestInfoProviderTest {
 	@Test
 	public void nr01_query_example_default() throws Exception {
 		assertEquals(null, getSwagger(new NR01()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
-		assertObjectEquals("{id:1}", getSwaggerWithFile(new NR01()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
+		assertEquals("{id:1}", getSwaggerWithFile(new NR01()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
 	}
 
-	@RestResource(swagger=@ResourceSwagger("paths:{'/path/{foo}/query':{get:{parameters:[{'in':'query',name:'foo',x-example:{id:2}}]}}}"))
+	@RestResource(swagger=@ResourceSwagger("paths:{'/path/{foo}/query':{get:{parameters:[{'in':'query',name:'foo',x-example:'{id:2}'}]}}}"))
 	public static class NR02 {
 		@RestMethod(name=GET,path="/path/{foo}/query")
 		public Foo doFoo(@Query("foo") Foo foo) {
@@ -1611,13 +1611,13 @@ public class BasicRestInfoProviderTest {
 
 	@Test
 	public void nr02_query_example_swaggerOnClass() throws Exception {
-		assertObjectEquals("{id:2}", getSwagger(new NR02()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
-		assertObjectEquals("{id:2}", getSwaggerWithFile(new NR02()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
+		assertEquals("{id:2}", getSwagger(new NR02()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
+		assertEquals("{id:2}", getSwaggerWithFile(new NR02()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
 	}
 
-	@RestResource(swagger=@ResourceSwagger("paths:{'/path/{foo}/query':{get:{parameters:[{'in':'query',name:'foo',x-example:{id:2}}]}}}"))
+	@RestResource(swagger=@ResourceSwagger("paths:{'/path/{foo}/query':{get:{parameters:[{'in':'query',name:'foo',x-example:'{id:2}'}]}}}"))
 	public static class NR03 {
-		@RestMethod(name=GET,path="/path/{foo}/query",swagger=@MethodSwagger("parameters:[{'in':'query',name:'foo',x-example:{id:3}}]"))
+		@RestMethod(name=GET,path="/path/{foo}/query",swagger=@MethodSwagger("parameters:[{'in':'query',name:'foo',x-example:'{id:3}'}]"))
 		public Foo doFoo() {
 			return null;
 		}
@@ -1625,11 +1625,11 @@ public class BasicRestInfoProviderTest {
 
 	@Test
 	public void nr03_query_example_swaggerOnMethod() throws Exception {
-		assertObjectEquals("{id:3}", getSwagger(new NR03()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
-		assertObjectEquals("{id:3}", getSwaggerWithFile(new NR03()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
+		assertEquals("{id:3}", getSwagger(new NR03()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
+		assertEquals("{id:3}", getSwaggerWithFile(new NR03()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
 	}
 
-	@RestResource(swagger=@ResourceSwagger("paths:{'/path/{foo}/query':{get:{parameters:[{'in':'query',name:'foo',x-example:{id:2}}]}}}"))
+	@RestResource(swagger=@ResourceSwagger("paths:{'/path/{foo}/query':{get:{parameters:[{'in':'query',name:'foo',x-example:'{id:2}'}]}}}"))
 	public static class NR04 {
 		@RestMethod(name=GET,path="/path/{foo}/query")
 		public Foo doFoo(@Query(name="foo",example="{id:4}") Foo foo) {
@@ -1639,11 +1639,11 @@ public class BasicRestInfoProviderTest {
 
 	@Test
 	public void nr04_query_example_swaggerOnAnnotation() throws Exception {
-		assertObjectEquals("{id:4}", getSwagger(new NR04()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
-		assertObjectEquals("{id:4}", getSwaggerWithFile(new NR04()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
+		assertEquals("{id:4}", getSwagger(new NR04()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
+		assertEquals("{id:4}", getSwaggerWithFile(new NR04()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
 	}
 
-	@RestResource(messages="BasicRestInfoProviderTest", swagger=@ResourceSwagger("paths:{'/path/{foo}/query':{get:{parameters:[{'in':'query',name:'foo',x-example:{id:2}}]}}}"))
+	@RestResource(messages="BasicRestInfoProviderTest", swagger=@ResourceSwagger("paths:{'/path/{foo}/query':{get:{parameters:[{'in':'query',name:'foo',x-example:'{id:2}'}]}}}"))
 	public static class NR05 {
 		@RestMethod(name=GET,path="/path/{foo}/query")
 		public Foo doFoo(@Query(name="foo",example="{id:$L{5}}") Foo foo) {
@@ -1653,8 +1653,8 @@ public class BasicRestInfoProviderTest {
 
 	@Test
 	public void nr05_query_example_swaggerOnAnnotation_localized() throws Exception {
-		assertObjectEquals("{id:5}", getSwagger(new NR05()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
-		assertObjectEquals("{id:5}", getSwaggerWithFile(new NR05()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
+		assertEquals("{id:5}", getSwagger(new NR05()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
+		assertEquals("{id:5}", getSwaggerWithFile(new NR05()).getPaths().get("/path/{foo}/query").get("get").getParameter("query", "foo").getExample());
 	}
 
 	//=================================================================================================================
@@ -2002,12 +2002,12 @@ public class BasicRestInfoProviderTest {
 	@Test
 	public void oc01a_responses_100_example_default() throws Exception {
 		assertEquals(null, getSwagger(new OC01a()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
-		assertObjectEquals("{foo:'a'}", getSwaggerWithFile(new OC01a()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
+		assertEquals("{foo:'a'}", getSwaggerWithFile(new OC01a()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
 	}
 	@Test
 	public void oc01b_responses_100_example_default() throws Exception {
 		assertEquals(null, getSwagger(new OC01b()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
-		assertObjectEquals("{foo:'a'}", getSwaggerWithFile(new OC01b()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
+		assertEquals("{foo:'a'}", getSwaggerWithFile(new OC01b()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
 	}
 
 	@RestResource(swagger=@ResourceSwagger("paths:{'/path/{foo}/responses/100':{get:{responses:{100:{example:{foo:'b'}}}}}}"))
@@ -2049,13 +2049,13 @@ public class BasicRestInfoProviderTest {
 
 	@Test
 	public void oc04a_response_100_example_swaggerOnAnnotation() throws Exception {
-		assertObjectEquals("{foo:'d'}", getSwagger(new OC04a()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
-		assertObjectEquals("{foo:'d'}", getSwaggerWithFile(new OC04a()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
+		assertEquals("{foo:'d'}", getSwagger(new OC04a()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
+		assertEquals("{foo:'d'}", getSwaggerWithFile(new OC04a()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
 	}
 	@Test
 	public void oc04b_response_100_example_swaggerOnAnnotation() throws Exception {
-		assertObjectEquals("{foo:'d'}", getSwagger(new OC04b()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
-		assertObjectEquals("{foo:'d'}", getSwaggerWithFile(new OC04b()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
+		assertEquals("{foo:'d'}", getSwagger(new OC04b()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
+		assertEquals("{foo:'d'}", getSwaggerWithFile(new OC04b()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
 	}
 
 	@RestResource(messages="BasicRestInfoProviderTest", swagger=@ResourceSwagger("paths:{'/path/{foo}/responses/100':{get:{responses:{100:{example:{foo:'b'}}}}}}"))
@@ -2073,13 +2073,13 @@ public class BasicRestInfoProviderTest {
 
 	@Test
 	public void oc05a_response_100_example_swaggerOnAnnotation_localized() throws Exception {
-		assertObjectEquals("{foo:'l-foo'}", getSwagger(new OC05a()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
-		assertObjectEquals("{foo:'l-foo'}", getSwaggerWithFile(new OC05a()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
+		assertEquals("{foo:'l-foo'}", getSwagger(new OC05a()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
+		assertEquals("{foo:'l-foo'}", getSwaggerWithFile(new OC05a()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
 	}
 	@Test
 	public void oc05b_response_100_example_swaggerOnAnnotation_localized() throws Exception {
-		assertObjectEquals("{foo:'l-foo'}", getSwagger(new OC05b()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
-		assertObjectEquals("{foo:'l-foo'}", getSwaggerWithFile(new OC05b()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
+		assertEquals("{foo:'l-foo'}", getSwagger(new OC05b()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
+		assertEquals("{foo:'l-foo'}", getSwaggerWithFile(new OC05b()).getPaths().get("/path/{foo}/responses/100").get("get").getResponse(100).getExample());
 	}
 
 	//=================================================================================================================
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/BodyAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/BodyAnnotationTest.java
index 4076780..4de9ad7 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/BodyAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/BodyAnnotationTest.java
@@ -818,8 +818,8 @@ public class BodyAnnotationTest {
 			"description:'a\nb',",
 			"required:true,",
 			"schema:{type:'string'},",
-			"example:'a',",
-			"examples:{foo:'bar'}"
+			"x-example:'\\'a\\'',",
+			"x-examples:{foo:'bar'}"
 		})
 		public static class SA02 {
 			public SA02(String x) {}
@@ -832,12 +832,12 @@ public class BodyAnnotationTest {
 				"description:'a\nb',",
 				"required:true,",
 				"schema:{type:'string'},",
-				"example:'a',",
-				"examples:{foo:'bar'}"
+				"x-example:'\\'a\\'',",
+				"x-examples:{foo:'bar'}"
 			},
 			description={"b","c"},
 			schema=@Schema(type="string"),
-			example="b",
+			example="'b'",
 			examples="{foo:'baz'}"
 		)
 		public static class SA03 {
@@ -853,7 +853,7 @@ public class BodyAnnotationTest {
 		assertEquals("a\nb", x.getDescription());
 		assertObjectEquals("true", x.getRequired());
 		assertObjectEquals("{type:'string'}", x.getSchema());
-		assertObjectEquals("'a'", x.getExample());
+		assertEquals("'a'", x.getExample());
 		assertObjectEquals("{foo:'bar'}", x.getExamples());
 	}
 	@Test
@@ -862,7 +862,7 @@ public class BodyAnnotationTest {
 		assertEquals("a\nb", x.getDescription());
 		assertObjectEquals("true", x.getRequired());
 		assertObjectEquals("{type:'string'}", x.getSchema());
-		assertObjectEquals("'a'", x.getExample());
+		assertEquals("'a'", x.getExample());
 		assertObjectEquals("{foo:'bar'}", x.getExamples());
 	}
 	@Test
@@ -871,7 +871,7 @@ public class BodyAnnotationTest {
 		assertEquals("b\nc", x.getDescription());
 		assertObjectEquals("true", x.getRequired());
 		assertObjectEquals("{type:'string'}", x.getSchema());
-		assertObjectEquals("'b'", x.getExample());
+		assertEquals("'b'", x.getExample());
 		assertObjectEquals("{foo:'baz'}", x.getExamples());
 	}
 
@@ -952,7 +952,7 @@ public class BodyAnnotationTest {
 	@Test
 	public void sc01_Body_onPojo_example() throws Exception {
 		ParameterInfo x = getSwagger(new SC()).getPaths().get("/example").get("get").getParameter("body", null);
-		assertObjectEquals("{f1:'b'}", x.getExample());
+		assertEquals("{f1:'b'}", x.getExample());
 	}
 	@Test
 	public void sc02_Body_onPojo_examples() throws Exception {
@@ -981,7 +981,7 @@ public class BodyAnnotationTest {
 				description= {"a","b"},
 				required=true,
 				schema=@Schema(type="string"),
-				example="'a'",
+				example="a",
 				examples=" {foo:'bar'} "
 			) TA01 b) {}
 
@@ -995,8 +995,8 @@ public class BodyAnnotationTest {
 				"description:'a\nb',",
 				"required:true,",
 				"schema:{type:'string'},",
-				"example:'a',",
-				"examples:{foo:'bar'}"
+				"x-example:'a',",
+				"x-examples:{foo:'bar'}"
 			}) TA02 b) {}
 
 		public static class TA03 {
@@ -1010,8 +1010,8 @@ public class BodyAnnotationTest {
 					"description:'a\nb',",
 					"required:true,",
 					"schema:{type:'string'},",
-					"example:'a',",
-					"examples:{foo:'bar'}"
+					"x-example:'a',",
+					"x-examples:{foo:'bar'}"
 				},
 				description= {"b","c"},
 				schema=@Schema(type="string"),
@@ -1026,7 +1026,7 @@ public class BodyAnnotationTest {
 		assertEquals("a\nb", x.getDescription());
 		assertObjectEquals("true", x.getRequired());
 		assertObjectEquals("{type:'string'}", x.getSchema());
-		assertObjectEquals("'a'", x.getExample());
+		assertEquals("a", x.getExample());
 		assertObjectEquals("{foo:'bar'}", x.getExamples());
 	}
 	@Test
@@ -1035,7 +1035,7 @@ public class BodyAnnotationTest {
 		assertEquals("a\nb", x.getDescription());
 		assertObjectEquals("true", x.getRequired());
 		assertObjectEquals("{type:'string'}", x.getSchema());
-		assertObjectEquals("'a'", x.getExample());
+		assertEquals("a", x.getExample());
 		assertObjectEquals("{foo:'bar'}", x.getExamples());
 	}
 	@Test
@@ -1044,7 +1044,7 @@ public class BodyAnnotationTest {
 		assertEquals("b\nc", x.getDescription());
 		assertObjectEquals("true", x.getRequired());
 		assertObjectEquals("{type:'string'}", x.getSchema());
-		assertObjectEquals("'b'", x.getExample());
+		assertEquals("b", x.getExample());
 		assertObjectEquals("{foo:'baz'}", x.getExamples());
 	}
 
@@ -1134,7 +1134,7 @@ public class BodyAnnotationTest {
 	@Test
 	public void tc01_Body_onParameter_example() throws Exception {
 		ParameterInfo x = getSwagger(new TC()).getPaths().get("/example").get("get").getParameter("body", null);
-		assertObjectEquals("{f1:'b'}", x.getExample());
+		assertEquals("{f1:'b'}", x.getExample());
 	}
 	@Test
 	public void tc02_Body_onParameter_examples() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/FormDataAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/FormDataAnnotationTest.java
index 7426cd5..30d5bec 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/FormDataAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/FormDataAnnotationTest.java
@@ -320,7 +320,7 @@ public class FormDataAnnotationTest {
 	@Test
 	public void sc01_FormData_onPojo_example() throws Exception {
 		ParameterInfo x = getSwagger(new SC()).getPaths().get("/example").get("get").getParameter("formData", "F");
-		assertObjectEquals("{f1:'a'}", x.getExample());
+		assertEquals("{f1:'a'}", x.getExample());
 	}
 
 	//=================================================================================================================
@@ -473,6 +473,6 @@ public class FormDataAnnotationTest {
 	@Test
 	public void tc01_FormData_onParameter_example() throws Exception {
 		ParameterInfo x = getSwagger(new TC()).getPaths().get("/example").get("get").getParameter("formData", "F");
-		assertObjectEquals("{f1:'a'}", x.getExample());
+		assertEquals("{f1:'a'}", x.getExample());
 	}
 }
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HeaderAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HeaderAnnotationTest.java
index d1e84a7..1e15e62 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HeaderAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HeaderAnnotationTest.java
@@ -183,7 +183,7 @@ public class HeaderAnnotationTest {
 	@Test
 	public void sc01_Header_onPojo_example() throws Exception {
 		ParameterInfo x = getSwagger(new SC()).getPaths().get("/example").get("get").getParameter("header", "H");
-		assertObjectEquals("{f1:'a'}", x.getExample());
+		assertEquals("{f1:'a'}", x.getExample());
 	}
 
 	//=================================================================================================================
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/PathAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/PathAnnotationTest.java
index 1f88c7a..f8e8903 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/PathAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/PathAnnotationTest.java
@@ -369,7 +369,7 @@ public class PathAnnotationTest {
 		assertEquals("string", x.getType());
 		assertObjectEquals("{type:'string'}", x.getSchema());
 		assertObjectEquals("['a','b']", x.getEnum());
-		assertObjectEquals("'a'", x.getExample());
+		assertEquals("'a'", x.getExample());
 	}
 	@Test
 	public void sa02_Path_onPojo_api() throws Exception {
@@ -379,7 +379,7 @@ public class PathAnnotationTest {
 		assertEquals("string", x.getType());
 		assertObjectEquals("{type:'string'}", x.getSchema());
 		assertObjectEquals("['a','b']", x.getEnum());
-		assertObjectEquals("'a'", x.getExample());
+		assertEquals("a", x.getExample());
 	}
 	@Test
 	public void sa03_Path_onPojo_mixed() throws Exception {
@@ -389,7 +389,7 @@ public class PathAnnotationTest {
 		assertEquals("string", x.getType());
 		assertObjectEquals("{type:'string'}", x.getSchema());
 		assertObjectEquals("['a','b']", x.getEnum());
-		assertObjectEquals("'a'", x.getExample());
+		assertEquals("'a'", x.getExample());
 	}
 	@Test
 	public void sa04_Path_onPojo_value() throws Exception {
@@ -474,7 +474,7 @@ public class PathAnnotationTest {
 	@Test
 	public void sc01_Path_onPojo_example() throws Exception {
 		ParameterInfo x = getSwagger(new SC()).getPaths().get("/example/{P}").get("get").getParameter("path", "P");
-		assertObjectEquals("{f1:'a'}", x.getExample());
+		assertEquals("{f1:'a'}", x.getExample());
 	}
 
 	//=================================================================================================================
@@ -629,6 +629,6 @@ public class PathAnnotationTest {
 	@Test
 	public void tc01_Path_onParameter_example2() throws Exception {
 		ParameterInfo x = getSwagger(new TC()).getPaths().get("/example/{P}").get("get").getParameter("path", "P");
-		assertObjectEquals("{f1:'b'}", x.getExample());
+		assertEquals("{f1:'b'}", x.getExample());
 	}
 }
\ No newline at end of file
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/QueryAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/QueryAnnotationTest.java
index ea28f9b..19048b5 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/QueryAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/QueryAnnotationTest.java
@@ -431,7 +431,7 @@ public class QueryAnnotationTest {
 	@Test
 	public void sc01_Query_onPojo_example() throws Exception {
 		ParameterInfo x = getSwagger(new SC()).getPaths().get("/example").get("get").getParameter("query", "Q");
-		assertObjectEquals("{f1:'a'}", x.getExample());
+		assertEquals("{f1:'a'}", x.getExample());
 	}
 
 	//=================================================================================================================
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseAnnotationTest.java
index b2fe4a1..867dfdd 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseAnnotationTest.java
@@ -566,7 +566,7 @@ public class ResponseAnnotationTest {
 		assertEquals("a\nb", x.getDescription());
 		assertObjectEquals("{type:'string'}", x.getSchema());
 		assertObjectEquals("{foo:{type:'string'}}", x.getHeaders());
-		assertObjectEquals("'a'", x.getExample());
+		assertEquals("'a'", x.getExample());
 		assertObjectEquals("{foo:'a'}", x.getExamples());
 	}
 	@Test
@@ -575,7 +575,7 @@ public class ResponseAnnotationTest {
 		assertEquals("a\nb", x.getDescription());
 		assertObjectEquals("{type:'string'}", x.getSchema());
 		assertObjectEquals("{foo:{type:'string'}}", x.getHeaders());
-		assertObjectEquals("'a'", x.getExample());
+		assertEquals("'a'", x.getExample());
 		assertObjectEquals("{foo:'a'}", x.getExamples());
 	}
 	@Test
@@ -584,7 +584,7 @@ public class ResponseAnnotationTest {
 		assertEquals("a\nb", x.getDescription());
 		assertObjectEquals("{type:'string'}", x.getSchema());
 		assertObjectEquals("{foo:{type:'string'}}", x.getHeaders());
-		assertObjectEquals("'a'", x.getExample());
+		assertEquals("a", x.getExample());
 		assertObjectEquals("{foo:'a'}", x.getExamples());
 	}
 	@Test
@@ -593,7 +593,7 @@ public class ResponseAnnotationTest {
 		assertEquals("a\nb", x.getDescription());
 		assertObjectEquals("{type:'string'}", x.getSchema());
 		assertObjectEquals("{foo:{type:'string'}}", x.getHeaders());
-		assertObjectEquals("'a'", x.getExample());
+		assertEquals("a", x.getExample());
 		assertObjectEquals("{foo:'a'}", x.getExamples());
 	}
 	@Test
@@ -602,7 +602,7 @@ public class ResponseAnnotationTest {
 		assertEquals("a\nb", x.getDescription());
 		assertObjectEquals("{type:'string'}", x.getSchema());
 		assertObjectEquals("{foo:{type:'string'}}", x.getHeaders());
-		assertObjectEquals("'a'", x.getExample());
+		assertEquals("'a'", x.getExample());
 		assertObjectEquals("{foo:'a'}", x.getExamples());
 	}
 	@Test
@@ -611,7 +611,7 @@ public class ResponseAnnotationTest {
 		assertEquals("a\nb", x.getDescription());
 		assertObjectEquals("{type:'string'}", x.getSchema());
 		assertObjectEquals("{bar:{type:'number'},foo:{type:'string'}}", x.getHeaders());
-		assertObjectEquals("'a'", x.getExample());
+		assertEquals("'a'", x.getExample());
 		assertObjectEquals("{foo:'a'}", x.getExamples());
 	}
 	@Test
@@ -751,12 +751,12 @@ public class ResponseAnnotationTest {
 	@Test
 	public void sc01a_Response_onPojo_example() throws Exception {
 		ResponseInfo x = getSwagger(new SC()).getPaths().get("/sc01a").get("get").getResponse(200);
-		assertObjectEquals("{f1:'a'}", x.getExample());
+		assertEquals("{f1:'a'}", x.getExample());
 	}
 	@Test
 	public void sc01b_Response_onPojo_example() throws Exception {
 		ResponseInfo x = getSwagger(new SC()).getPaths().get("/sc01b").get("get").getResponse(200);
-		assertObjectEquals("{f1:'a'}", x.getExample());
+		assertEquals("{f1:'a'}", x.getExample());
 	}
 	@Test
 	public void sc02a_Response_onPojo_examples() throws Exception {
@@ -845,7 +845,7 @@ public class ResponseAnnotationTest {
 		assertEquals("a\nb", x.getDescription());
 		assertObjectEquals("{type:'string'}", x.getSchema());
 		assertObjectEquals("{foo:{type:'string'}}", x.getHeaders());
-		assertObjectEquals("'a'", x.getExample());
+		assertEquals("'a'", x.getExample());
 		assertObjectEquals("{foo:'a'}", x.getExamples());
 	}
 	@Test
@@ -863,7 +863,7 @@ public class ResponseAnnotationTest {
 		assertEquals("a\nb", x.getDescription());
 		assertObjectEquals("{type:'string'}", x.getSchema());
 		assertObjectEquals("{bar:{type:'number'},foo:{type:'string'}}", x.getHeaders());
-		assertObjectEquals("'a'", x.getExample());
+		assertEquals("'a'", x.getExample());
 		assertObjectEquals("{foo:'a'}", x.getExamples());
 	}
 	@Test
@@ -924,7 +924,7 @@ public class ResponseAnnotationTest {
 	@Test
 	public void uc01_Response_onThrowable_example() throws Exception {
 		ResponseInfo x = getSwagger(new UC()).getPaths().get("/example").get("get").getResponse(500);
-		assertObjectEquals("{f1:'b'}", x.getExample());
+		assertEquals("{f1:'b'}", x.getExample());
 	}
 	@Test
 	public void uc02_Response_onThrowable_examples() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/BasicRestInfoProviderTest_swagger.json b/juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/BasicRestInfoProviderTest_swagger.json
index 7db7fe2..e2b4b8a 100644
--- a/juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/BasicRestInfoProviderTest_swagger.json
+++ b/juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/BasicRestInfoProviderTest_swagger.json
@@ -90,9 +90,7 @@
 						schema: {
 							$ref: '#/definitions/Foo'
 						},
-						'x-example': {
-							id:1
-						}
+						'x-example': "{id:1}"
 					}
 				]
 			}
@@ -121,9 +119,7 @@
 						schema: {
 							$ref: '#/definitions/Foo'
 						},						
-						'x-example': {
-							id:1
-						},
+						'x-example': "{id:1}",
 						'x-examples': {
 							foo: 'a'
 						}						
@@ -149,7 +145,7 @@
 								description: 's-description'
 							}
 						},
-						x-example: {foo:'a'},
+						x-example: "{foo:'a'}",
 						examples: {
 							foo: 'a'
 						}