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 2022/06/20 12:34:04 UTC

[juneau] branch master updated: Modernize OpenAPI DTOs API.

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 f7992953e Modernize OpenAPI DTOs API.
f7992953e is described below

commit f7992953e56ac8cbac503825d00daeb2120bb785
Author: JamesBognar <ja...@salesforce.com>
AuthorDate: Mon Jun 20 08:33:38 2022 -0400

    Modernize OpenAPI DTOs API.
---
 .../org/apache/juneau/dto/openapi/Contact.java     |  23 +-
 .../apache/juneau/dto/openapi/Discriminator.java   |  34 +-
 .../org/apache/juneau/dto/openapi/Encoding.java    | 666 ++++++++++----------
 .../org/apache/juneau/dto/openapi/Example.java     |  31 +-
 .../juneau/dto/openapi/ExternalDocumentation.java  |  19 +-
 .../org/apache/juneau/dto/openapi/HeaderInfo.java  |  80 +--
 .../java/org/apache/juneau/dto/openapi/Info.java   |  34 +-
 .../java/org/apache/juneau/dto/openapi/Items.java  |  89 ++-
 .../org/apache/juneau/dto/openapi/License.java     |  19 +-
 .../java/org/apache/juneau/dto/openapi/Link.java   |  59 +-
 .../org/apache/juneau/dto/openapi/MediaType.java   | 537 ++++++++--------
 .../org/apache/juneau/dto/openapi/OAuthFlow.java   |  59 +-
 .../org/apache/juneau/dto/openapi/OAuthFlows.java  |  20 +-
 .../apache/juneau/dto/openapi/OpenApiElement.java  |  28 +-
 .../apache/juneau/dto/openapi/RequestBodyInfo.java | 446 +++++++------
 .../org/apache/juneau/dto/openapi/Response.java    | 696 ++++++++++-----------
 .../org/apache/juneau/dto/openapi/SchemaInfo.java  | 175 +++---
 .../juneau/dto/openapi/SecuritySchemeInfo.java     |  50 +-
 .../java/org/apache/juneau/dto/openapi/Server.java | 453 +++++++-------
 .../apache/juneau/dto/openapi/ServerVariable.java  | 538 ++++++++--------
 .../java/org/apache/juneau/dto/openapi/Tag.java    |  22 +-
 .../java/org/apache/juneau/dto/openapi/Xml.java    |  27 +-
 .../apache/juneau/internal/CollectionUtils.java    |  11 +
 .../16.juneau-petstore/01.jp.Installing.html       |  28 -
 .../Topics/16.juneau-petstore/02.jp.Running.html   |  34 -
 .../Topics/16.juneau-petstore/03.jp.Building.html  |  31 -
 .../docs/Topics/16.juneau-petstore/04.jp.App.html  |  80 ---
 .../juneau/examples/rest/springboot/App.java       |   8 +
 28 files changed, 1971 insertions(+), 2326 deletions(-)

diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Contact.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Contact.java
index 3bedc60d1..99003cfca 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Contact.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Contact.java
@@ -12,21 +12,19 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
 import org.apache.juneau.UriResolver;
 import org.apache.juneau.annotation.Bean;
-import org.apache.juneau.dto.swagger.SwaggerElement;
 import org.apache.juneau.internal.MultiSet;
 import org.apache.juneau.internal.StringUtils;
-import org.apache.juneau.utils.ASet;
 
 import java.net.URI;
 import java.net.URL;
 import java.util.Set;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.toStringVal;
-import static org.apache.juneau.internal.BeanPropertyUtils.toType;
-import static org.apache.juneau.internal.StringUtils.isNotEmpty;
-
 /**
  * Contact information for the exposed API.
  *
@@ -127,7 +125,7 @@ public class Contact extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Contact name(Object value) {
-		return setName(toStringVal(value));
+		return setName(stringify(value));
 	}
 
 	/**
@@ -215,7 +213,7 @@ public class Contact extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Contact email(Object value) {
-		return setEmail(toStringVal(value));
+		return setEmail(stringify(value));
 	}
 
 	/**
@@ -273,10 +271,11 @@ public class Contact extends OpenApiElement {
 
 	@Override /* OpenApiElement */
 	public Set<String> keySet() {
-		ASet<String> s = new ASet<String>()
-			.appendIf(name != null, "name")
-			.appendIf(url != null, "url")
-			.appendIf(email != null, "email");
+		Set<String> s = setBuilder(String.class)
+			.addIf(name != null, "name")
+			.addIf(url != null, "url")
+			.addIf(email != null, "email")
+			.build();
 		return new MultiSet<>(s, super.keySet());
 	}
 }
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Discriminator.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Discriminator.java
index 602339b57..d7452cfdd 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Discriminator.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Discriminator.java
@@ -12,18 +12,18 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
 import org.apache.juneau.UriResolver;
 import org.apache.juneau.annotation.Bean;
 import org.apache.juneau.internal.MultiSet;
-import org.apache.juneau.utils.ASet;
 
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.*;
-import static org.apache.juneau.internal.StringUtils.isNotEmpty;
-
 /**
  * Used to aid in serialization, deserialization, and validation.
  */
@@ -101,7 +101,7 @@ public class Discriminator extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Discriminator propertyName(Object value) {
-		return setPropertyName(toStringVal(value));
+		return setPropertyName(stringify(value));
 	}
 
 	/**
@@ -129,7 +129,7 @@ public class Discriminator extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Discriminator setMapping(Map<String,String> value) {
-		mapping = newMap(value);
+		mapping = copyOf(value);
 		return this;
 	}
 
@@ -142,18 +142,7 @@ public class Discriminator extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Discriminator addMapping(Map<String,String> values) {
-		mapping = addToMap(mapping, values);
-		return this;
-	}
-
-	/**
-	 * Same as {@link #setMapping(Map<String,String>)}.
-	 *
-	 * @param values
-	 * @return This object (for method chaining).
-	 */
-	public Discriminator mapping(Object...values) {
-		mapping = addToMap(mapping, values, String.class, String.class);
+		mapping = mapBuilder(mapping).sparse().addAll(values).build();
 		return this;
 	}
 
@@ -183,7 +172,7 @@ public class Discriminator extends OpenApiElement {
 			return this;
 		switch (property) {
 			case "propertyName": return propertyName(value);
-			case "mapping": return mapping(value);
+			case "mapping": return setMapping(mapBuilder(String.class,String.class).sparse().addAny(value).build());
 			default:
 				super.set(property, value);
 				return this;
@@ -192,9 +181,10 @@ public class Discriminator extends OpenApiElement {
 
 	@Override /* OpenApiElement */
 	public Set<String> keySet() {
-		ASet<String> s = new ASet<String>()
-			.appendIf(propertyName != null, "propertyName")
-			.appendIf(mapping != null, "mapping");
+		Set<String> s = setBuilder(String.class)
+			.addIf(propertyName != null, "propertyName")
+			.addIf(mapping != null, "mapping")
+			.build();
 		return new MultiSet<>(s, super.keySet());
 	}
 }
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Encoding.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Encoding.java
index 3a021e300..8156a6e40 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Encoding.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Encoding.java
@@ -12,352 +12,342 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
 import org.apache.juneau.UriResolver;
 import org.apache.juneau.annotation.Bean;
 import org.apache.juneau.internal.MultiSet;
-import org.apache.juneau.internal.StringUtils;
-import org.apache.juneau.utils.ASet;
-
 import java.net.URI;
 import java.net.URL;
 import java.util.*;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.*;
-
+/**
+ * TODO
+ */
 @Bean(properties="contentType,style,explode,headers,allowReserved,*")
 public class Encoding extends OpenApiElement{
 
-    private String contentType,
-            style;
-    private Map<String,HeaderInfo> headers;
-    private Boolean explode,
-            allowReserved;
-
-    /**
-     * Default constructor.
-     */
-    public Encoding() { }
-
-    /**
-     * Copy constructor.
-     *
-     * @param copyFrom The object to copy.
-     */
-    public Encoding(Encoding copyFrom) {
-        super(copyFrom);
-
-        this.contentType = copyFrom.contentType;
-        this.style = copyFrom.style;
-        this.explode = copyFrom.explode;
-        this.allowReserved = copyFrom.allowReserved;
-        if (copyFrom.headers == null) {
-            this.headers = null;
-        } else {
-            this.headers = new LinkedHashMap<>();
-            for (Map.Entry<String,HeaderInfo> e : copyFrom.headers.entrySet())
-                this.headers.put(e.getKey(),	e.getValue().copy());
-        }
-    }
-
-    /**
-     * Make a deep copy of this object.
-     *
-     * @return A deep copy of this object.
-     */
-    public Encoding copy() {
-        return new Encoding(this);
-    }
-
-    @Override /* OpenApiElement */
-    protected Encoding strict() {
-        super.strict();
-        return this;
-    }
-
-    /**
-     * Bean property getter:  <property>contentType</property>.
-     *
-     * <p>
-     * The URL pointing to the contact information.
-     *
-     * @return The property value, or <jk>null</jk> if it is not set.
-     */
-    public String getContentType() {
-        return contentType;
-    }
-
-    /**
-     * Bean property setter:  <property>url</property>.
-     *
-     * <p>
-     * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}.
-     * <br>Strings must be valid URIs.
-     *
-     * <p>
-     * URIs defined by {@link UriResolver} can be used for values.
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public Encoding setContentType(String value) {
-        contentType = value;
-        return this;
-    }
-
-    /**
-     * Same as {@link #setContentType(String)}.
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Non-URI values will be converted to URI using <code><jk>new</jk> URI(value.toString())</code>.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public Encoding contentType(Object value) {
-        return setContentType(toStringVal(value));
-    }
-
-    /**
-     * Bean property getter:  <property>style</property>.
-     */
-    public String getStyle() {
-        return style;
-    }
-
-    /**
-     * Bean property setter:  <property>description</property>.
-     *
-     * @param value
-     * 	The new value for this property.
-     * @return This object (for method chaining).
-     */
-    public Encoding setStyle(String value) {
-        style = value;
-        return this;
-    }
-
-    /**
-     * Same as {@link #setStyle(String)}.
-     *
-     * @param value
-     * 	The new value for this property.
-     * @return This object (for method chaining).
-     */
-    public Encoding style(Object value) {
-        return setStyle(toStringVal(value));
-    }
-
-    /**
-     * Bean property getter:  <property>variables</property>.
-     */
-    public Map<String, HeaderInfo> getHeaders() {
-        return headers;
-    }
-
-    /**
-     * Bean property setter:  <property>variables</property>.
-     *
-     * @param value
-     * 	The new value for this property.
-     * @return This object (for method chaining).
-     */
-    public Encoding setHeaders(Map<String, HeaderInfo> value) {
-        headers = newMap(value);
-        return this;
-    }
-
-    /**
-     * Adds one or more values to the <property>headers</property> property.
-     *
-     * @param value
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public Encoding addHeader(Map<String, HeaderInfo> value) {
-        headers = addToMap(headers,value);
-        return this;
-    }
-
-    /**
-     * Adds one or more values to the <property>variables</property> property.
-     *
-     * @param value
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public Encoding addHeaders(String keyval, HeaderInfo value) {
-        headers = addToMap(headers,keyval,value);
-        return this;
-    }
-
-    /**
-     * Adds a single value to the <property>headers</property> property.
-     *
-     * @param name variable name.
-     * @param value The server variable instance.
-     * @return This object (for method chaining).
-     */
-    public Encoding header(String name, HeaderInfo value) {
-        addHeader(Collections.singletonMap(name, value));
-        return this;
-    }
-
-    /**
-     * Adds one or more values to the <property>headers</property> property.
-     *
-     * @param values
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public Encoding headers(Object...values) {
-        headers = addToMap(headers, values, String.class, HeaderInfo.class);
-        return this;
-    }
-
-    public Encoding headers(Object value) {
-        return setHeaders((HashMap<String,HeaderInfo>)value);
-    }
-
-
-    /**
-     * Bean property getter:  <property>required</property>.
-     *
-     * <p>
-     * The type of the object.
-     *
-     * @return The property value, or <jk>null</jk> if it is not set.
-     */
-    public Boolean getExplode() {
-        return explode;
-    }
-
-    /**
-     * Bean property setter:  <property>explode</property>.
-     *
-     * <p>
-     * The type of the object.
-     *
-     * <h5 class='section'>See Also:</h5>
-     * <ul class='doctree'>
-     * 	<li class='extlink'>{@doc SwaggerDataTypes}
-     * </ul>
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Property value is required.
-     * 	</ul>
-     * @return This object (for method chaining).
-     */
-    public Encoding setExplode(Boolean value) {
-        explode = value;
-        return this;
-    }
-
-    /**
-     * Same as {@link #setExplode(Boolean)}
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Non-String values will be converted to String using <code>toBoolean()</code>.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public Encoding explode(Object value) {
-        return setExplode(toBoolean(value));
-    }
-
-
-    /**
-     * Bean property getter:  <property>required</property>.
-     *
-     * <p>
-     * The type of the object.
-     *
-     * @return The property value, or <jk>null</jk> if it is not set.
-     */
-    public Boolean getAllowReserved() {
-        return allowReserved;
-    }
-
-    /**
-     * Bean property setter:  <property>explode</property>.
-     *
-     * <p>
-     * The type of the object.
-     *
-     * <h5 class='section'>See Also:</h5>
-     * <ul class='doctree'>
-     * 	<li class='extlink'>{@doc SwaggerDataTypes}
-     * </ul>
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Property value is required.
-     * 	</ul>
-     * @return This object (for method chaining).
-     */
-    public Encoding setAllowReserved(Boolean value) {
-        allowReserved = value;
-        return this;
-    }
-
-    /**
-     * Same as {@link #setExplode(Boolean)}
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Non-String values will be converted to String using <code>toBoolean()</code>.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public Encoding allowReserved(Object value) {
-        return setAllowReserved(toBoolean(value));
-    }
-
-
-    @Override /* OpenApiElement */
-    public <T> T get(String property, Class<T> type) {
-        if (property == null)
-            return null;
-        switch (property) {
-            case "contentType": return toType(getContentType(), type);
-            case "style": return toType(getStyle(), type);
-            case "headers": return toType(getHeaders(), type);
-            case "explode": return toType(getExplode(), type);
-            case "allowReserved": return toType(getAllowReserved(), type);
-            default: return super.get(property, type);
-        }
-    }
-
-    @Override /* OpenApiElement */
-    public Encoding set(String property, Object value) {
-        if (property == null)
-            return this;
-        switch (property) {
-            case "contentType": return contentType(value);
-            case "style": return style(value);
-            case "headers": return headers(value);
-            case "explode": return explode(value);
-            case "allowReserved": return allowReserved(value);
-            default:
-                super.set(property, value);
-                return this;
-        }
-    }
-
-    @Override /* OpenApiElement */
-    public Set<String> keySet() {
-        ASet<String> s = new ASet<String>()
-                .appendIf(contentType != null, "contentType")
-                .appendIf(style != null, "style")
-                .appendIf(headers != null, "headers")
-                .appendIf(explode != null, "explode")
-                .appendIf(allowReserved != null, "allowReserved");
-        return new MultiSet<>(s, super.keySet());
-    }
+	private String contentType,
+			style;
+	private Map<String,HeaderInfo> headers;
+	private Boolean explode,
+			allowReserved;
+
+	/**
+	 * Default constructor.
+	 */
+	public Encoding() { }
+
+	/**
+	 * Copy constructor.
+	 *
+	 * @param copyFrom The object to copy.
+	 */
+	public Encoding(Encoding copyFrom) {
+		super(copyFrom);
+
+		this.contentType = copyFrom.contentType;
+		this.style = copyFrom.style;
+		this.explode = copyFrom.explode;
+		this.allowReserved = copyFrom.allowReserved;
+		if (copyFrom.headers == null) {
+			this.headers = null;
+		} else {
+			this.headers = new LinkedHashMap<>();
+			for (Map.Entry<String,HeaderInfo> e : copyFrom.headers.entrySet())
+				this.headers.put(e.getKey(),	e.getValue().copy());
+		}
+	}
+
+	/**
+	 * Make a deep copy of this object.
+	 *
+	 * @return A deep copy of this object.
+	 */
+	public Encoding copy() {
+		return new Encoding(this);
+	}
+
+	@Override /* OpenApiElement */
+	protected Encoding strict() {
+		super.strict();
+		return this;
+	}
+
+	/**
+	 * Bean property getter:  <property>contentType</property>.
+	 *
+	 * <p>
+	 * The URL pointing to the contact information.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public String getContentType() {
+		return contentType;
+	}
+
+	/**
+	 * Bean property setter:  <property>url</property>.
+	 *
+	 * <p>
+	 * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}.
+	 * <br>Strings must be valid URIs.
+	 *
+	 * <p>
+	 * URIs defined by {@link UriResolver} can be used for values.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public Encoding setContentType(String value) {
+		contentType = value;
+		return this;
+	}
+
+	/**
+	 * Same as {@link #setContentType(String)}.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Non-URI values will be converted to URI using <code><jk>new</jk> URI(value.toString())</code>.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public Encoding contentType(Object value) {
+		return setContentType(stringify(value));
+	}
+
+	/**
+	 * Bean property getter:  <property>style</property>.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public String getStyle() {
+		return style;
+	}
+
+	/**
+	 * Bean property setter:  <property>description</property>.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * @return This object (for method chaining).
+	 */
+	public Encoding setStyle(String value) {
+		style = value;
+		return this;
+	}
+
+	/**
+	 * Same as {@link #setStyle(String)}.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * @return This object (for method chaining).
+	 */
+	public Encoding style(Object value) {
+		return setStyle(stringify(value));
+	}
+
+	/**
+	 * Bean property getter:  <property>variables</property>.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public Map<String, HeaderInfo> getHeaders() {
+		return headers;
+	}
+
+	/**
+	 * Bean property setter:  <property>variables</property>.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * @return This object (for method chaining).
+	 */
+	public Encoding setHeaders(Map<String, HeaderInfo> value) {
+		headers = copyOf(value);
+		return this;
+	}
+
+	/**
+	 * Adds one or more values to the <property>headers</property> property.
+	 *
+	 * @param values
+	 * 	The values to add to this property.
+	 * 	<br>Ignored if <jk>null</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public Encoding addHeader(Map<String, HeaderInfo> values) {
+		headers = mapBuilder(headers).sparse().addAll(values).build();
+		return this;
+	}
+
+	/**
+	 * Adds one or more values to the <property>variables</property> property.
+	 *
+	 * @param key The mapping key.
+	 * @param value
+	 * 	The values to add to this property.
+	 * 	<br>Ignored if <jk>null</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public Encoding addHeaders(String key, HeaderInfo value) {
+		headers = mapBuilder(headers).sparse().add(key, value).build();
+		return this;
+	}
+
+	/**
+	 * Adds a single value to the <property>headers</property> property.
+	 *
+	 * @param name variable name.
+	 * @param value The server variable instance.
+	 * @return This object (for method chaining).
+	 */
+	public Encoding header(String name, HeaderInfo value) {
+		addHeader(Collections.singletonMap(name, value));
+		return this;
+	}
+
+	/**
+	 * Bean property getter:  <property>required</property>.
+	 *
+	 * <p>
+	 * The type of the object.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public Boolean getExplode() {
+		return explode;
+	}
+
+	/**
+	 * Bean property setter:  <property>explode</property>.
+	 *
+	 * <p>
+	 * The type of the object.
+	 *
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul class='doctree'>
+	 * 	<li class='extlink'>{@doc SwaggerDataTypes}
+	 * </ul>
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Property value is required.
+	 * 	</ul>
+	 * @return This object (for method chaining).
+	 */
+	public Encoding setExplode(Boolean value) {
+		explode = value;
+		return this;
+	}
+
+	/**
+	 * Same as {@link #setExplode(Boolean)}
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Non-String values will be converted to String using <code>toBoolean()</code>.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public Encoding explode(Object value) {
+		return setExplode(toBoolean(value));
+	}
+
+
+	/**
+	 * Bean property getter:  <property>required</property>.
+	 *
+	 * <p>
+	 * The type of the object.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public Boolean getAllowReserved() {
+		return allowReserved;
+	}
+
+	/**
+	 * Bean property setter:  <property>explode</property>.
+	 *
+	 * <p>
+	 * The type of the object.
+	 *
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul class='doctree'>
+	 * 	<li class='extlink'>{@doc SwaggerDataTypes}
+	 * </ul>
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Property value is required.
+	 * 	</ul>
+	 * @return This object (for method chaining).
+	 */
+	public Encoding setAllowReserved(Boolean value) {
+		allowReserved = value;
+		return this;
+	}
+
+	/**
+	 * Same as {@link #setExplode(Boolean)}
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Non-String values will be converted to String using <code>toBoolean()</code>.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public Encoding allowReserved(Object value) {
+		return setAllowReserved(toBoolean(value));
+	}
+
+
+	@Override /* OpenApiElement */
+	public <T> T get(String property, Class<T> type) {
+		if (property == null)
+			return null;
+		switch (property) {
+			case "contentType": return toType(getContentType(), type);
+			case "style": return toType(getStyle(), type);
+			case "headers": return toType(getHeaders(), type);
+			case "explode": return toType(getExplode(), type);
+			case "allowReserved": return toType(getAllowReserved(), type);
+			default: return super.get(property, type);
+		}
+	}
+
+	@Override /* OpenApiElement */
+	public Encoding set(String property, Object value) {
+		if (property == null)
+			return this;
+		switch (property) {
+			case "contentType": return contentType(value);
+			case "style": return style(value);
+			case "headers": return setHeaders(mapBuilder(String.class,HeaderInfo.class).sparse().addAny(value).build());
+			case "explode": return explode(value);
+			case "allowReserved": return allowReserved(value);
+			default:
+				super.set(property, value);
+				return this;
+		}
+	}
+
+	@Override /* OpenApiElement */
+	public Set<String> keySet() {
+		Set<String> s = setBuilder(String.class)
+				.addIf(contentType != null, "contentType")
+				.addIf(style != null, "style")
+				.addIf(headers != null, "headers")
+				.addIf(explode != null, "explode")
+				.addIf(allowReserved != null, "allowReserved")
+				.build();
+		return new MultiSet<>(s, super.keySet());
+	}
 }
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Example.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Example.java
index d829487d4..4c8dcbe5c 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Example.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Example.java
@@ -12,20 +12,14 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
-import org.apache.juneau.UriResolver;
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
 import org.apache.juneau.annotation.Bean;
 import org.apache.juneau.internal.MultiSet;
-import org.apache.juneau.internal.StringUtils;
-import org.apache.juneau.utils.ASet;
-
-import java.net.URI;
-import java.net.URL;
 import java.util.Set;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.toStringVal;
-import static org.apache.juneau.internal.BeanPropertyUtils.toType;
-import static org.apache.juneau.internal.StringUtils.isNotEmpty;
-
 /**
  * information for Examples object.
  *
@@ -128,7 +122,7 @@ public class Example extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Example summary(Object value) {
-		return setSummary(toStringVal(value));
+		return setSummary(stringify(value));
 	}
 
 	/**
@@ -165,7 +159,7 @@ public class Example extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Example description(Object value) {
-		return setDescription(toStringVal(value));
+		return setDescription(stringify(value));
 	}
 
 	/**
@@ -208,7 +202,7 @@ public class Example extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Example externalValue(Object value) {
-		return setExternalValue(toStringVal(value));
+		return setExternalValue(stringify(value));
 	}
 
 	/**
@@ -295,11 +289,12 @@ public class Example extends OpenApiElement {
 
 	@Override /* OpenApiElement */
 	public Set<String> keySet() {
-		ASet<String> s = new ASet<String>()
-			.appendIf(description != null, "description")
-				.appendIf(summary != null, "summary")
-				.appendIf(externalValue != null, "externalValue")
-			.appendIf(value != null, "value");
+		Set<String> s = setBuilder(String.class)
+			.addIf(description != null, "description")
+				.addIf(summary != null, "summary")
+				.addIf(externalValue != null, "externalValue")
+			.addIf(value != null, "value")
+			.build();
 		return new MultiSet<>(s, super.keySet());
 	}
 }
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/ExternalDocumentation.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/ExternalDocumentation.java
index 98b37337e..44e485d4e 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/ExternalDocumentation.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/ExternalDocumentation.java
@@ -12,21 +12,19 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
 import org.apache.juneau.UriResolver;
 import org.apache.juneau.annotation.Bean;
-import org.apache.juneau.dto.swagger.SwaggerElement;
 import org.apache.juneau.internal.MultiSet;
 import org.apache.juneau.internal.StringUtils;
-import org.apache.juneau.utils.ASet;
 
 import java.net.URI;
 import java.net.URL;
 import java.util.Set;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.toStringVal;
-import static org.apache.juneau.internal.BeanPropertyUtils.toType;
-import static org.apache.juneau.internal.StringUtils.isNotEmpty;
-
 /**
  * Allows referencing an external resource for extended documentation.
  */
@@ -101,7 +99,7 @@ public class ExternalDocumentation extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public ExternalDocumentation description(Object value) {
-		return setDescription(toStringVal(value));
+		return setDescription(stringify(value));
 	}
 
 	/**
@@ -198,9 +196,10 @@ public class ExternalDocumentation extends OpenApiElement {
 
 	@Override /* OpenApiElement */
 	public Set<String> keySet() {
-		ASet<String> s = new ASet<String>()
-			.appendIf(description != null, "description")
-			.appendIf(url != null, "url");
+		Set<String> s = setBuilder(String.class)
+			.addIf(description != null, "description")
+			.addIf(url != null, "url")
+			.build();
 		return new MultiSet<>(s, super.keySet());
 	}
 }
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/HeaderInfo.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/HeaderInfo.java
index 09f9369e3..9aafacd4d 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/HeaderInfo.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/HeaderInfo.java
@@ -12,19 +12,15 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
-import org.apache.juneau.annotation.Bean;
-import org.apache.juneau.annotation.BeanProperty;
-import org.apache.juneau.dto.swagger.ResponseInfo;
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
+import org.apache.juneau.annotation.*;
 import org.apache.juneau.dto.swagger.Swagger;
 import org.apache.juneau.internal.MultiSet;
-import org.apache.juneau.internal.StringUtils;
-import org.apache.juneau.utils.ASet;
-
 import java.util.*;
 
-import static org.apache.juneau.internal.ArrayUtils.contains;
-import static org.apache.juneau.internal.BeanPropertyUtils.*;
-
 /**
  * Describes a single HTTP header.
  *
@@ -56,9 +52,6 @@ import static org.apache.juneau.internal.BeanPropertyUtils.*;
 @SuppressWarnings({"unchecked"})
 public class HeaderInfo extends OpenApiElement {
 
-	private static final String[] VALID_TYPES = {"string", "number", "integer", "boolean", "array"};
-	private static final String[] VALID_COLLECTION_FORMATS = {"csv","ssv","tsv","pipes","multi"};
-
 	private String
 		description,
 		ref;
@@ -156,7 +149,7 @@ public class HeaderInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public HeaderInfo description(Object value) {
-		return setDescription(toStringVal(value));
+		return setDescription(stringify(value));
 	}
 
 	/**
@@ -434,7 +427,7 @@ public class HeaderInfo extends OpenApiElement {
 	 *
 	 * @return The property value, or <jk>null</jk> if it is not set.
 	 */
-	@BeanProperty("$ref")
+	@Beanp("$ref")
 	public String getRef() {
 		return ref;
 	}
@@ -456,9 +449,9 @@ public class HeaderInfo extends OpenApiElement {
 	 * 	<br>Can be <jk>null</jk> to unset the property.
 	 * @return This object (for method chaining).
 	 */
-	@BeanProperty("$ref")
+	@Beanp("$ref")
 	public HeaderInfo setRef(Object value) {
-		ref = StringUtils.asString(value);
+		ref = stringify(value);
 		return this;
 	}
 
@@ -479,7 +472,7 @@ public class HeaderInfo extends OpenApiElement {
 	 *
 	 * @return The property value, or <jk>null</jk> if it is not set.
 	 */
-	@BeanProperty("x-example")
+	@Beanp("x-example")
 	public Object getExample() {
 		return example;
 	}
@@ -492,7 +485,7 @@ public class HeaderInfo extends OpenApiElement {
 	 * 	<br>Can be <jk>null</jk> to unset the property.
 	 * @return This object (for method chaining).
 	 */
-	@BeanProperty("x-example")
+	@Beanp("x-example")
 	public HeaderInfo setExample(Object value) {
 		example = value;
 		return this;
@@ -536,7 +529,7 @@ public class HeaderInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public HeaderInfo setExamples(Map<String,Example> value) {
-		examples = newMap(value);
+		examples = copyOf(value);
 		return this;
 	}
 
@@ -549,7 +542,7 @@ public class HeaderInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public HeaderInfo addExamples(Map<String,Example> values) {
-		examples = addToMap(examples, values);
+		examples = mapBuilder(examples).sparse().addAll(values).build();
 		return this;
 	}
 
@@ -564,28 +557,6 @@ public class HeaderInfo extends OpenApiElement {
 		addExamples(Collections.singletonMap(name, example));
 		return this;
 	}
-	/**
-	 * Adds one or more values to the <property>examples</property> property.
-	 *
-	 * @param values
-	 * 	The values to add to this property.
-	 * 	<br>Valid types:
-	 * 	<ul>
-	 * 		<li><code>Map&lt;String,{@link org.apache.juneau.dto.swagger.HeaderInfo}|String&gt;</code>
-	 * 		<li><code>String</code> - JSON object representation of <code>Map&lt;String,{@link org.apache.juneau.dto.swagger.HeaderInfo}&gt;</code>
-	 * 			<h5 class='figure'>Example:</h5>
-	 * 			<p class='bcode w800'>
-	 * 	headers(<js>"{headerName:{description:'description',...}}"</js>);
-	 * 			</p>
-	 * 	</ul>
-	 * 	<br>Ignored if <jk>null</jk>.
-	 * @return This object (for method chaining).
-	 */
-	public HeaderInfo examples(Object...values) {
-		examples = addToMap(examples,values, String.class, Example.class);
-		return this;
-	}
-
 
 	@Override /* OpenApiElement */
 	public <T> T get(String property, Class<T> type) {
@@ -619,7 +590,7 @@ public class HeaderInfo extends OpenApiElement {
 			case "$ref": return ref(value);
 			case "schema": return schema(value);
 			case "x-example": return example(value);
-			case "examples": return setExamples(null).examples(value);
+			case "examples": return setExamples(mapBuilder(String.class,Example.class).sparse().addAny(value).build());
 			default:
 				super.set(property, value);
 				return this;
@@ -628,17 +599,18 @@ public class HeaderInfo extends OpenApiElement {
 
 	@Override /* SwaggerElement */
 	public Set<String> keySet() {
-		ASet<String> s = new ASet<String>()
-			.appendIf(description != null, "description")
-			.appendIf(required != null, "required")
-			.appendIf(explode != null, "explode")
-			.appendIf(deprecated != null, "deprecated")
-			.appendIf(allowEmptyValue != null, "allowEmptyValue")
-			.appendIf(ref != null, "$ref")
-			.appendIf(allowReserved != null, "allowReserved")
-			.appendIf(schema != null, "schema")
-			.appendIf(example != null, "example")
-			.appendIf(examples != null, "examples");
+		Set<String> s = setBuilder(String.class)
+			.addIf(description != null, "description")
+			.addIf(required != null, "required")
+			.addIf(explode != null, "explode")
+			.addIf(deprecated != null, "deprecated")
+			.addIf(allowEmptyValue != null, "allowEmptyValue")
+			.addIf(ref != null, "$ref")
+			.addIf(allowReserved != null, "allowReserved")
+			.addIf(schema != null, "schema")
+			.addIf(example != null, "example")
+			.addIf(examples != null, "examples")
+			.build();
 		return new MultiSet<>(s, super.keySet());
 
 	}
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Info.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Info.java
index 32f1b51ed..4664a1028 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Info.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Info.java
@@ -12,19 +12,16 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
 import org.apache.juneau.annotation.Bean;
 import org.apache.juneau.dto.swagger.Contact;
 import org.apache.juneau.dto.swagger.License;
-import org.apache.juneau.dto.swagger.SwaggerElement;
 import org.apache.juneau.internal.MultiSet;
-import org.apache.juneau.utils.ASet;
-
 import java.util.Set;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.toStringVal;
-import static org.apache.juneau.internal.BeanPropertyUtils.toType;
-import static org.apache.juneau.internal.StringUtils.isNotEmpty;
-
 /**
  * The object provides metadata about the API.
  *
@@ -154,7 +151,7 @@ public class Info extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Info title(Object value) {
-		return setTitle(toStringVal(value));
+		return setTitle(stringify(value));
 	}
 
 	/**
@@ -197,7 +194,7 @@ public class Info extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Info description(Object value) {
-		return setDescription(toStringVal(value));
+		return setDescription(stringify(value));
 	}
 
 	/**
@@ -238,7 +235,7 @@ public class Info extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Info termsOfService(Object value) {
-		return setTermsOfService(toStringVal(value));
+		return setTermsOfService(stringify(value));
 	}
 
 	/**
@@ -377,7 +374,7 @@ public class Info extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Info version(Object value) {
-		return setVersion(toStringVal(value));
+		return setVersion(stringify(value));
 	}
 
 
@@ -451,13 +448,14 @@ public class Info extends OpenApiElement {
 
 	@Override /* OpenApiElement */
 	public Set<String> keySet() {
-		ASet<String> s = new ASet<String>()
-			.appendIf(title != null, "title")
-			.appendIf(description != null, "description")
-			.appendIf(termsOfService != null, "termsOfService")
-			.appendIf(contact != null, "contact")
-			.appendIf(license != null, "license")
-			.appendIf(version != null, "version");
+		Set<String> s = setBuilder(String.class)
+			.addIf(title != null, "title")
+			.addIf(description != null, "description")
+			.addIf(termsOfService != null, "termsOfService")
+			.addIf(contact != null, "contact")
+			.addIf(license != null, "license")
+			.addIf(version != null, "version")
+			.build();
 		return new MultiSet<>(s, super.keySet());
 	}
 }
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Items.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Items.java
index 63fb18453..6a7b8019f 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Items.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Items.java
@@ -12,22 +12,20 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
-import org.apache.juneau.FormattedRuntimeException;
-import org.apache.juneau.ObjectList;
-import org.apache.juneau.ObjectMap;
-import org.apache.juneau.annotation.Bean;
-import org.apache.juneau.annotation.BeanProperty;
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.collections.*;
 import org.apache.juneau.dto.swagger.Swagger;
-import org.apache.juneau.dto.swagger.SwaggerElement;
 import org.apache.juneau.internal.MultiSet;
-import org.apache.juneau.internal.StringUtils;
 import org.apache.juneau.json.SimpleJsonSerializer;
-import org.apache.juneau.utils.ASet;
 
 import java.util.*;
 
 import static org.apache.juneau.internal.ArrayUtils.contains;
-import static org.apache.juneau.internal.BeanPropertyUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
 
 /**
  * A limited subset of JSON-Schema's items object.
@@ -117,7 +115,7 @@ public class Items extends OpenApiElement {
 		this.uniqueItems = copyFrom.uniqueItems;
 		this.items = copyFrom.items == null ? null : copyFrom.items.copy();
 		this._default = copyFrom._default;
-		this._enum = newList(copyFrom._enum);
+		this._enum = copyOf(copyFrom._enum);
 		this.ref = copyFrom.ref;
 	}
 
@@ -200,7 +198,7 @@ public class Items extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Items type(Object value) {
-		return setType(toStringVal(value));
+		return setType(stringify(value));
 	}
 
 	/**
@@ -251,7 +249,7 @@ public class Items extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Items format(Object value) {
-		return setFormat(toStringVal(value));
+		return setFormat(stringify(value));
 	}
 
 	/**
@@ -337,10 +335,10 @@ public class Items extends OpenApiElement {
 	 */
 	public Items setCollectionFormat(String value) {
 		if (isStrict() && ! contains(value, VALID_COLLECTION_FORMATS))
-			throw new FormattedRuntimeException(
+			throw BasicRuntimeException.create().message(
 				"Invalid value passed in to setCollectionFormat(String).  Value=''{0}'', valid values={1}",
 				value, VALID_COLLECTION_FORMATS
-			);
+			).build();
 		collectionFormat = value;
 		return this;
 	}
@@ -362,7 +360,7 @@ public class Items extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Items collectionFormat(Object value) {
-		return setCollectionFormat(toStringVal(value));
+		return setCollectionFormat(stringify(value));
 	}
 
 	/**
@@ -746,7 +744,7 @@ public class Items extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Items pattern(Object value) {
-		return setPattern(toStringVal(value));
+		return setPattern(stringify(value));
 	}
 
 	/**
@@ -912,7 +910,7 @@ public class Items extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Items setEnum(Collection<Object> value) {
-		_enum = newList(value);
+		_enum = listFrom(value);
 		return this;
 	}
 
@@ -925,7 +923,7 @@ public class Items extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Items addEnum(Collection<Object> values) {
-		_enum = addToList(_enum, values);
+		_enum = listBuilder(_enum).sparse().addAny(values).build();
 		return this;
 	}
 
@@ -953,7 +951,7 @@ public class Items extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Items _enum(Object...values) {
-		_enum = addToList(_enum, values, Object.class);
+		_enum = listBuilder(_enum).sparse().addAny(values).build();
 		return this;
 	}
 
@@ -1007,7 +1005,7 @@ public class Items extends OpenApiElement {
 	 *
 	 * @return The property value, or <jk>null</jk> if it is not set.
 	 */
-	@BeanProperty("$ref")
+	@Beanp("$ref")
 	public String getRef() {
 		return ref;
 	}
@@ -1029,9 +1027,9 @@ public class Items extends OpenApiElement {
 	 * 	<br>Can be <jk>null</jk> to unset the property.
 	 * @return This object (for method chaining).
 	 */
-	@BeanProperty("$ref")
+	@Beanp("$ref")
 	public Items setRef(Object value) {
-		ref = StringUtils.asString(value);
+		ref = stringify(value);
 		return this;
 	}
 
@@ -1105,25 +1103,26 @@ public class Items extends OpenApiElement {
 
 	@Override /* SwaggerElement */
 	public Set<String> keySet() {
-		ASet<String> s = new ASet<String>()
-			.appendIf(type != null, "type")
-			.appendIf(format != null, "format")
-			.appendIf(items != null, "items")
-			.appendIf(collectionFormat != null, "collectionFormat")
-			.appendIf(_default != null, "default")
-			.appendIf(maximum != null, "maximum")
-			.appendIf(exclusiveMaximum != null, "exclusiveMaximum")
-			.appendIf(minimum != null, "minimum")
-			.appendIf(exclusiveMinimum != null, "exclusiveMinimum")
-			.appendIf(maxLength != null, "maxLength")
-			.appendIf(minLength != null, "minLength")
-			.appendIf(pattern != null, "pattern")
-			.appendIf(maxItems != null, "maxItems")
-			.appendIf(minItems != null, "minItems")
-			.appendIf(uniqueItems != null, "uniqueItems")
-			.appendIf(_enum != null, "enum")
-			.appendIf(multipleOf != null, "multipleOf")
-			.appendIf(ref != null, "$ref");
+		Set<String> s = setBuilder(String.class)
+			.addIf(type != null, "type")
+			.addIf(format != null, "format")
+			.addIf(items != null, "items")
+			.addIf(collectionFormat != null, "collectionFormat")
+			.addIf(_default != null, "default")
+			.addIf(maximum != null, "maximum")
+			.addIf(exclusiveMaximum != null, "exclusiveMaximum")
+			.addIf(minimum != null, "minimum")
+			.addIf(exclusiveMinimum != null, "exclusiveMinimum")
+			.addIf(maxLength != null, "maxLength")
+			.addIf(minLength != null, "minLength")
+			.addIf(pattern != null, "pattern")
+			.addIf(maxItems != null, "maxItems")
+			.addIf(minItems != null, "minItems")
+			.addIf(uniqueItems != null, "uniqueItems")
+			.addIf(_enum != null, "enum")
+			.addIf(multipleOf != null, "multipleOf")
+			.addIf(ref != null, "$ref")
+			.build();
 		return new MultiSet<>(s, super.keySet());
 	}
 
@@ -1163,8 +1162,8 @@ public class Items extends OpenApiElement {
 
 	/* Resolve references in extra attributes */
 	private Object resolveRefs(Object o, Swagger swagger, Deque<String> refStack, int maxDepth) {
-		if (o instanceof ObjectMap) {
-			ObjectMap om = (ObjectMap)o;
+		if (o instanceof JsonMap) {
+			JsonMap om = (JsonMap)o;
 			Object ref = om.get("$ref");
 			if (ref instanceof CharSequence) {
 				String sref = ref.toString();
@@ -1179,8 +1178,8 @@ public class Items extends OpenApiElement {
 			for (Map.Entry<String,Object> e : om.entrySet())
 				e.setValue(resolveRefs(e.getValue(), swagger, refStack, maxDepth));
 		}
-		if (o instanceof ObjectList)
-			for (ListIterator<Object> li = ((ObjectList)o).listIterator(); li.hasNext();)
+		if (o instanceof JsonList)
+			for (ListIterator<Object> li = ((JsonList)o).listIterator(); li.hasNext();)
 				li.set(resolveRefs(li.next(), swagger, refStack, maxDepth));
 		return o;
 	}
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/License.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/License.java
index 7e716de4f..d8727cc4b 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/License.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/License.java
@@ -12,21 +12,19 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
 import org.apache.juneau.UriResolver;
 import org.apache.juneau.annotation.Bean;
-import org.apache.juneau.dto.swagger.SwaggerElement;
 import org.apache.juneau.internal.MultiSet;
 import org.apache.juneau.internal.StringUtils;
-import org.apache.juneau.utils.ASet;
 
 import java.net.URI;
 import java.net.URL;
 import java.util.Set;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.toStringVal;
-import static org.apache.juneau.internal.BeanPropertyUtils.toType;
-import static org.apache.juneau.internal.StringUtils.isNotEmpty;
-
 /**
  * License information for the exposed API.
  *
@@ -124,7 +122,7 @@ public class License extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public License name(Object value) {
-		return setName(toStringVal(value));
+		return setName(stringify(value));
 	}
 
 	/**
@@ -220,9 +218,10 @@ public class License extends OpenApiElement {
 
 	@Override /* OpenApiElement */
 	public Set<String> keySet() {
-		ASet<String> s = new ASet<String>()
-			.appendIf(name != null, "name")
-			.appendIf(url != null, "url");
+		Set<String> s = setBuilder(String.class)
+			.addIf(name != null, "name")
+			.addIf(url != null, "url")
+			.build();
 		return new MultiSet<>(s, super.keySet());
 	}
 }
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Link.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Link.java
index e4184aa6b..316cfc6de 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Link.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Link.java
@@ -12,16 +12,17 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
 import org.apache.juneau.annotation.Bean;
 import org.apache.juneau.internal.MultiSet;
-import org.apache.juneau.utils.ASet;
 
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.*;
-
 /**
  * information for Link object.
  *
@@ -133,7 +134,7 @@ public class Link extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Link operationRef(Object value) {
-		return setOperationRef(toStringVal(value));
+		return setOperationRef(stringify(value));
 	}
 
 	/**
@@ -170,7 +171,7 @@ public class Link extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Link description(Object value) {
-		return setDescription(toStringVal(value));
+		return setDescription(stringify(value));
 	}
 
 	/**
@@ -213,7 +214,7 @@ public class Link extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Link operationId(Object value) {
-		return setOperationId(toStringVal(value));
+		return setOperationId(stringify(value));
 	}
 
 	/**
@@ -330,7 +331,7 @@ public class Link extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Link setParameters(Map<String,Object> value) {
-		parameters = newMap(value);
+		parameters = copyOf(value);
 		return this;
 	}
 
@@ -343,7 +344,7 @@ public class Link extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Link addParameters(Map<String,Object> values) {
-		parameters = addToMap(parameters, values);
+		parameters = mapBuilder(parameters).sparse().addAll(values).build();
 		return this;
 	}
 
@@ -355,33 +356,10 @@ public class Link extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Link parameter(String mimeType, Object parameter) {
-		parameters = addToMap(parameters, mimeType, parameter);
-		return this;
-	}
-
-	/**
-	 * Adds one or more values to the <property>examples</property> property.
-	 *
-	 * @param values
-	 * 	The values to add to this property.
-	 * 	<br>Valid types:
-	 * 	<ul>
-	 * 		<li><code>Map&lt;String,Object&gt;</code>
-	 * 		<li><code>String</code> - JSON object representation of <code>Map&lt;String,Object&gt;</code>
-	 * 			<h5 class='figure'>Example:</h5>
-	 * 			<p class='bcode w800'>
-	 * 	examples(<js>"{'text/json':{foo:'bar'}}"</js>);
-	 * 			</p>
-	 * 	</ul>
-	 * 	<br>Ignored if <jk>null</jk>.
-	 * @return This object (for method chaining).
-	 */
-	public Link parameters(Object...values) {
-		parameters = addToMap(parameters, values, String.class, Object.class);
+		parameters = mapBuilder(parameters).sparse().add(mimeType, parameters).build();
 		return this;
 	}
 
-
 	@Override /* OpenApiElement */
 	public <T> T get(String property, Class<T> type) {
 		if (property == null)
@@ -407,7 +385,7 @@ public class Link extends OpenApiElement {
 			case "operationRef": return operationRef(value);
 			case "requestBody": return requestBody(value);
 			case "server": return server(value);
-			case "parameters": return parameters(value);
+			case "parameters": return setParameters(mapBuilder(String.class,Object.class).sparse().addAny(value).build());
 			default:
 				super.set(property, value);
 				return this;
@@ -416,13 +394,14 @@ public class Link extends OpenApiElement {
 
 	@Override /* OpenApiElement */
 	public Set<String> keySet() {
-		ASet<String> s = new ASet<String>()
-			.appendIf(description != null, "description")
-			.appendIf(operationId != null, "operationId")
-			.appendIf(operationRef != null, "operationRef")
-			.appendIf(requestBody != null, "requestBody")
-			.appendIf(parameters != null, "parameters")
-			.appendIf(server != null, "server");
+		Set<String> s = setBuilder(String.class)
+			.addIf(description != null, "description")
+			.addIf(operationId != null, "operationId")
+			.addIf(operationRef != null, "operationRef")
+			.addIf(requestBody != null, "requestBody")
+			.addIf(parameters != null, "parameters")
+			.addIf(server != null, "server")
+			.build();
 		return new MultiSet<>(s, super.keySet());
 	}
 }
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/MediaType.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/MediaType.java
index d5454d490..afbf65766 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/MediaType.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/MediaType.java
@@ -12,315 +12,290 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
-import org.apache.juneau.UriResolver;
-import org.apache.juneau.annotation.Bean;
-import org.apache.juneau.annotation.BeanProperty;
-import org.apache.juneau.internal.MultiSet;
-import org.apache.juneau.internal.StringUtils;
-import org.apache.juneau.utils.ASet;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
 
-import java.net.URI;
-import java.net.URL;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.internal.MultiSet;
 import java.util.*;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.*;
-
+/**
+ * TODO
+ */
 @Bean(properties="schema,example,examples,encoding,*")
 public class MediaType extends OpenApiElement{
-    private SchemaInfo schema;
-    private Object example;
-    private Map<String,Example> examples;
-    private Map<String,Encoding> encoding;
-
-    /**
-     * Default constructor.
-     */
-    public MediaType() { }
-
-    /**
-     * Copy constructor.
-     *
-     * @param copyFrom The object to copy.
-     */
-    public MediaType(MediaType copyFrom) {
-        super(copyFrom);
+	private SchemaInfo schema;
+	private Object example;
+	private Map<String,Example> examples;
+	private Map<String,Encoding> encoding;
 
-        this.schema = copyFrom.schema;
-        this.example = copyFrom.example;
-        if (copyFrom.examples == null)
-            this.examples = null;
-        else
-            this.examples = new LinkedHashMap<>();
-        for (Map.Entry<String,Example> e : copyFrom.examples.entrySet())
-            this.examples.put(e.getKey(),	e.getValue().copy());
+	/**
+	 * Default constructor.
+	 */
+	public MediaType() { }
 
-        if (copyFrom.encoding == null)
-            this.encoding = null;
-        else
-            this.encoding = new LinkedHashMap<>();
-        for (Map.Entry<String,Encoding> e : copyFrom.encoding.entrySet())
-            this.encoding.put(e.getKey(),	e.getValue().copy());
-    }
+	/**
+	 * Copy constructor.
+	 *
+	 * @param copyFrom The object to copy.
+	 */
+	public MediaType(MediaType copyFrom) {
+		super(copyFrom);
 
-    /**
-     * Make a deep copy of this object.
-     *
-     * @return A deep copy of this object.
-     */
-    public MediaType copy() {
-        return new MediaType(this);
-    }
+		this.schema = copyFrom.schema;
+		this.example = copyFrom.example;
+		if (copyFrom.examples == null)
+			this.examples = null;
+		else
+			this.examples = new LinkedHashMap<>();
+		for (Map.Entry<String,Example> e : copyFrom.examples.entrySet())
+			this.examples.put(e.getKey(),	e.getValue().copy());
 
-    @Override /* OpenApiElement */
-    protected MediaType strict() {
-        super.strict();
-        return this;
-    }
+		if (copyFrom.encoding == null)
+			this.encoding = null;
+		else
+			this.encoding = new LinkedHashMap<>();
+		for (Map.Entry<String,Encoding> e : copyFrom.encoding.entrySet())
+			this.encoding.put(e.getKey(),	e.getValue().copy());
+	}
 
-    /**
-     * Bean property getter:  <property>schema</property>.
-     *
-     * @return The property value, or <jk>null</jk> if it is not set.
-     */
-    public SchemaInfo getSchema() {
-        return schema;
-    }
+	/**
+	 * Make a deep copy of this object.
+	 *
+	 * @return A deep copy of this object.
+	 */
+	public MediaType copy() {
+		return new MediaType(this);
+	}
 
-    /**
-     * Bean property setter:  <property>schema</property>.
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public MediaType setSchema(SchemaInfo value) {
-        schema = value;
-        return this;
-    }
+	@Override /* OpenApiElement */
+	protected MediaType strict() {
+		super.strict();
+		return this;
+	}
 
-    /**
-     * Same as {@link #setSchema(SchemaInfo)}.
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Valid types:
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public MediaType schema(Object value) {
-        return setSchema(toType(value, SchemaInfo.class));
-    }
+	/**
+	 * Bean property getter:  <property>schema</property>.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public SchemaInfo getSchema() {
+		return schema;
+	}
 
+	/**
+	 * Bean property setter:  <property>schema</property>.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public MediaType setSchema(SchemaInfo value) {
+		schema = value;
+		return this;
+	}
 
-    /**
-     * Bean property getter:  <property>x-example</property>.
-     *
-     * @return The property value, or <jk>null</jk> if it is not set.
-     */
-    @BeanProperty("x-example")
-    public Object getExample() {
-        return example;
-    }
+	/**
+	 * Same as {@link #setSchema(SchemaInfo)}.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Valid types:
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public MediaType schema(Object value) {
+		return setSchema(toType(value, SchemaInfo.class));
+	}
 
-    /**
-     * Bean property setter:  <property>examples</property>.
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    @BeanProperty("x-example")
-    public MediaType setExample(Object value) {
-        example = value;
-        return this;
-    }
 
-    /**
-     * Bean property setter:  <property>examples</property>.
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public MediaType example(Object value) {
-        example = value;
-        return this;
-    }
+	/**
+	 * Bean property getter:  <property>x-example</property>.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	@Beanp("x-example")
+	public Object getExample() {
+		return example;
+	}
 
-    /**
-     * Bean property getter:  <property>variables</property>.
-     */
-    public Map<String, Encoding> getEncoding() {
-        return encoding;
-    }
+	/**
+	 * Bean property setter:  <property>examples</property>.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	@Beanp("x-example")
+	public MediaType setExample(Object value) {
+		example = value;
+		return this;
+	}
 
-    /**
-     * Bean property setter:  <property>variables</property>.
-     *
-     * @param value
-     * 	The new value for this property.
-     * @return This object (for method chaining).
-     */
-    public MediaType setEncoding(Map<String, Encoding> value) {
-        encoding = newMap(value);
-        return this;
-    }
+	/**
+	 * Bean property setter:  <property>examples</property>.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public MediaType example(Object value) {
+		example = value;
+		return this;
+	}
 
-    /**
-     * Adds one or more values to the <property>encoding</property> property.
-     *
-     * @param value
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public MediaType addEncoding(Map<String, Encoding> value) {
-        encoding = addToMap(encoding,value);
-        return this;
-    }
+	/**
+	 * Bean property getter:  <property>variables</property>.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public Map<String, Encoding> getEncoding() {
+		return encoding;
+	}
 
-    /**
-     * Adds one or more values to the <property>variables</property> property.
-     *
-     * @param value
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public MediaType addEncoding(String keyval, Encoding value) {
-        encoding = addToMap(encoding,keyval,value);
-        return this;
-    }
+	/**
+	 * Bean property setter:  <property>variables</property>.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * @return This object (for method chaining).
+	 */
+	public MediaType setEncoding(Map<String, Encoding> value) {
+		encoding = copyOf(value);
+		return this;
+	}
 
-    /**
-     * Adds a single value to the <property>headers</property> property.
-     *
-     * @param name variable name.
-     * @param value The server variable instance.
-     * @return This object (for method chaining).
-     */
-    public MediaType encoding(String name, Encoding value) {
-        addEncoding(Collections.singletonMap(name, value));
-        return this;
-    }
+	/**
+	 * Adds one or more values to the <property>encoding</property> property.
+	 *
+	 * @param values
+	 * 	The values to add to this property.
+	 * 	<br>Ignored if <jk>null</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public MediaType addEncoding(Map<String, Encoding> values) {
+		encoding = mapBuilder(encoding).sparse().addAll(values).build();
+		return this;
+	}
 
-    public MediaType encoding(Object value) {
-        return setEncoding((HashMap<String,Encoding>)value);
-    }
+	/**
+	 * Adds one or more values to the <property>variables</property> property.
+	 *
+	 * @param key The mapping key.
+	 * @param value
+	 * 	The values to add to this property.
+	 * 	<br>Ignored if <jk>null</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public MediaType addEncoding(String key, Encoding value) {
+		encoding = mapBuilder(encoding).sparse().add(key, value).build();
+		return this;
+	}
 
+	/**
+	 * Adds a single value to the <property>headers</property> property.
+	 *
+	 * @param name variable name.
+	 * @param value The server variable instance.
+	 * @return This object (for method chaining).
+	 */
+	public MediaType encoding(String name, Encoding value) {
+		addEncoding(Collections.singletonMap(name, value));
+		return this;
+	}
 
-    /**
-     * Bean property getter:  <property>examples</property>.
-     *
-     * <p>
-     * The list of possible responses as they are returned from executing this operation.
-     *
-     * @return The property value, or <jk>null</jk> if it is not set.
-     */
-    public Map<String,Example> getExamples() {
-        return examples;
-    }
+	/**
+	 * Bean property getter:  <property>examples</property>.
+	 *
+	 * <p>
+	 * The list of possible responses as they are returned from executing this operation.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public Map<String,Example> getExamples() {
+		return examples;
+	}
 
-    /**
-     * Bean property setter:  <property>headers</property>.
-     *
-     * <p>
-     * A list of examples that are sent with the response.
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public MediaType setExamples(Map<String,Example> value) {
-        examples = newMap(value);
-        return this;
-    }
+	/**
+	 * Bean property setter:  <property>headers</property>.
+	 *
+	 * <p>
+	 * A list of examples that are sent with the response.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public MediaType setExamples(Map<String,Example> value) {
+		examples = copyOf(value);
+		return this;
+	}
 
-    /**
-     * Adds one or more values to the <property>headers</property> property.
-     *
-     * @param values
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public MediaType addExamples(Map<String,Example> values) {
-        examples = addToMap(examples, values);
-        return this;
-    }
+	/**
+	 * Adds one or more values to the <property>headers</property> property.
+	 *
+	 * @param values
+	 * 	The values to add to this property.
+	 * 	<br>Ignored if <jk>null</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public MediaType addExamples(Map<String,Example> values) {
+		examples = mapBuilder(examples).sparse().addAll(values).build();
+		return this;
+	}
 
-    /**
-     * Adds a single value to the <property>examples</property> property.
-     *
-     * @param name The example name.
-     * @param example The example.
-     * @return This object (for method chaining).
-     */
-    public MediaType example(String name, Example example) {
-        addExamples(Collections.singletonMap(name, example));
-        return this;
-    }
-    /**
-     * Adds one or more values to the <property>examples</property> property.
-     *
-     * @param values
-     * 	The values to add to this property.
-     * 	<br>Valid types:
-     * 	<ul>
-     * 		<li><code>Map&lt;String,{@link org.apache.juneau.dto.swagger.HeaderInfo}|String&gt;</code>
-     * 		<li><code>String</code> - JSON object representation of <code>Map&lt;String,{@link org.apache.juneau.dto.swagger.HeaderInfo}&gt;</code>
-     * 			<h5 class='figure'>Example:</h5>
-     * 			<p class='bcode w800'>
-     * 	headers(<js>"{headerName:{description:'description',...}}"</js>);
-     * 			</p>
-     * 	</ul>
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public MediaType examples(Object...values) {
-        examples = addToMap(examples,values, String.class, Example.class);
-        return this;
-    }
+	/**
+	 * Adds a single value to the <property>examples</property> property.
+	 *
+	 * @param name The example name.
+	 * @param example The example.
+	 * @return This object (for method chaining).
+	 */
+	public MediaType example(String name, Example example) {
+		addExamples(Collections.singletonMap(name, example));
+		return this;
+	}
 
-    @Override /* OpenApiElement */
-    public <T> T get(String property, Class<T> type) {
-        if (property == null)
-            return null;
-        switch (property) {
-            case "schema": return toType(getSchema(), type);
-            case "example": return toType(getExample(), type);
-            case "examples": return toType(getExamples(), type);
-            case "encoding": return toType(getEncoding(), type);
-            default: return super.get(property, type);
-        }
-    }
+	@Override /* OpenApiElement */
+	public <T> T get(String property, Class<T> type) {
+		if (property == null)
+			return null;
+		switch (property) {
+			case "schema": return toType(getSchema(), type);
+			case "example": return toType(getExample(), type);
+			case "examples": return toType(getExamples(), type);
+			case "encoding": return toType(getEncoding(), type);
+			default: return super.get(property, type);
+		}
+	}
 
-    @Override /* OpenApiElement */
-    public MediaType set(String property, Object value) {
-        if (property == null)
-            return this;
-        switch (property) {
-            case "schema": return schema(value);
-            case "example": return example(value);
-            case "examples": return examples(value);
-            case "encoding": return encoding(value);
-            default:
-                super.set(property, value);
-                return this;
-        }
-    }
+	@Override /* OpenApiElement */
+	public MediaType set(String property, Object value) {
+		if (property == null)
+			return this;
+		switch (property) {
+			case "schema": return schema(value);
+			case "example": return example(value);
+			case "examples": return setExamples(mapBuilder(String.class,Example.class).sparse().addAny(value).build());
+			case "encoding": return setEncoding(mapBuilder(String.class,Encoding.class).sparse().addAny(value).build());
+			default:
+				super.set(property, value);
+				return this;
+		}
+	}
 
-    @Override /* OpenApiElement */
-    public Set<String> keySet() {
-        ASet<String> s = new ASet<String>()
-                .appendIf(schema != null, "schema")
-                .appendIf(example != null, "example")
-                .appendIf(encoding != null, "encoding")
-                .appendIf(examples != null, "examples");
-        return new MultiSet<>(s, super.keySet());
-    }
+	@Override /* OpenApiElement */
+	public Set<String> keySet() {
+		Set<String> s = setBuilder(String.class)
+				.addIf(schema != null, "schema")
+				.addIf(example != null, "example")
+				.addIf(encoding != null, "encoding")
+				.addIf(examples != null, "examples")
+				.build();
+		return new MultiSet<>(s, super.keySet());
+	}
 }
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/OAuthFlow.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/OAuthFlow.java
index a627660ec..a753f0dc5 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/OAuthFlow.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/OAuthFlow.java
@@ -12,16 +12,17 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
 import org.apache.juneau.annotation.Bean;
 import org.apache.juneau.internal.MultiSet;
-import org.apache.juneau.utils.ASet;
 
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.*;
-
 /**
  * information for Link object.
  *
@@ -129,7 +130,7 @@ public class OAuthFlow extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public OAuthFlow authorizationUrl(Object value) {
-		return setAuthorizationUrl(toStringVal(value));
+		return setAuthorizationUrl(stringify(value));
 	}
 
 	/**
@@ -166,7 +167,7 @@ public class OAuthFlow extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public OAuthFlow tokenUrl(Object value) {
-		return setTokenUrl(toStringVal(value));
+		return setTokenUrl(stringify(value));
 	}
 
 	/**
@@ -209,7 +210,7 @@ public class OAuthFlow extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public OAuthFlow refreshUrl(Object value) {
-		return setRefreshUrl(toStringVal(value));
+		return setRefreshUrl(stringify(value));
 	}
 
 	/**
@@ -237,7 +238,7 @@ public class OAuthFlow extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public OAuthFlow setScopes(Map<String,String> value) {
-		scopes = newMap(value);
+		scopes = copyOf(value);
 		return this;
 	}
 
@@ -250,7 +251,7 @@ public class OAuthFlow extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public OAuthFlow addScopes(Map<String,String> values) {
-		scopes = addToMap(scopes, values);
+		scopes = mapBuilder(scopes).sparse().addAll(values).build();
 		return this;
 	}
 
@@ -258,37 +259,14 @@ public class OAuthFlow extends OpenApiElement {
 	 * Adds a single value to the <property>examples</property> property.
 	 *
 	 * @param name The mime-type string.
-	 * @param descriptiom The example.
-	 * @return This object (for method chaining).
-	 */
-	public OAuthFlow scopes(String name, String descriptiom) {
-		scopes = addToMap(scopes, name, descriptiom);
-		return this;
-	}
-
-	/**
-	 * Adds one or more values to the <property>examples</property> property.
-	 *
-	 * @param values
-	 * 	The values to add to this property.
-	 * 	<br>Valid types:
-	 * 	<ul>
-	 * 		<li><code>Map&lt;String,Object&gt;</code>
-	 * 		<li><code>String</code> - JSON object representation of <code>Map&lt;String,Object&gt;</code>
-	 * 			<h5 class='figure'>Example:</h5>
-	 * 			<p class='bcode w800'>
-	 * 	examples(<js>"{'text/json':{foo:'bar'}}"</js>);
-	 * 			</p>
-	 * 	</ul>
-	 * 	<br>Ignored if <jk>null</jk>.
+	 * @param description The example.
 	 * @return This object (for method chaining).
 	 */
-	public OAuthFlow scopes(Object...values) {
-		scopes = addToMap(scopes, values, String.class, String.class);
+	public OAuthFlow scopes(String name, String description) {
+		scopes = mapBuilder(scopes).sparse().add(name, description).build();
 		return this;
 	}
 
-
 	@Override /* OpenApiElement */
 	public <T> T get(String property, Class<T> type) {
 		if (property == null)
@@ -310,7 +288,7 @@ public class OAuthFlow extends OpenApiElement {
 			case "authorizationUrl": return authorizationUrl(value);
 			case "tokenUrl": return tokenUrl(value);
 			case "refreshUrl": return refreshUrl(value);
-			case "scopes": return scopes(value);
+			case "scopes": return setScopes(mapBuilder(String.class,String.class).sparse().addAny(value).build());
 			default:
 				super.set(property, value);
 				return this;
@@ -319,11 +297,12 @@ public class OAuthFlow extends OpenApiElement {
 
 	@Override /* OpenApiElement */
 	public Set<String> keySet() {
-		ASet<String> s = new ASet<String>()
-			.appendIf(authorizationUrl != null, "authorizationUrl")
-			.appendIf(tokenUrl != null, "tokenUrl")
-			.appendIf(refreshUrl != null, "refreshUrl")
-			.appendIf(scopes != null, "scopes");
+		Set<String> s = setBuilder(String.class)
+			.addIf(authorizationUrl != null, "authorizationUrl")
+			.addIf(tokenUrl != null, "tokenUrl")
+			.addIf(refreshUrl != null, "refreshUrl")
+			.addIf(scopes != null, "scopes")
+			.build();
 		return new MultiSet<>(s, super.keySet());
 	}
 }
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/OAuthFlows.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/OAuthFlows.java
index 666c225de..276cc08e6 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/OAuthFlows.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/OAuthFlows.java
@@ -12,18 +12,15 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
-import org.apache.juneau.FormattedRuntimeException;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
 import org.apache.juneau.annotation.Bean;
 import org.apache.juneau.dto.swagger.Items;
-import org.apache.juneau.dto.swagger.SchemaInfo;
 import org.apache.juneau.internal.MultiSet;
-import org.apache.juneau.utils.ASet;
 
 import java.util.Set;
 
-import static org.apache.juneau.internal.ArrayUtils.contains;
-import static org.apache.juneau.internal.BeanPropertyUtils.toStringVal;
-import static org.apache.juneau.internal.BeanPropertyUtils.toType;
+import static org.apache.juneau.internal.CollectionUtils.*;
 
 /**
  * Describes a single operation parameter.
@@ -370,11 +367,12 @@ public class OAuthFlows extends OpenApiElement {
 
 	@Override /* SwaggerElement */
 	public Set<String> keySet() {
-		ASet<String> s = new ASet<String>()
-			.appendIf(implicit != null, "implicit")
-			.appendIf(password != null, "password")
-			.appendIf(clientCredentials != null, "clientCredentials")
-			.appendIf(authorizationCode != null, "authorizationCode");
+		Set<String> s = setBuilder(String.class)
+			.addIf(implicit != null, "implicit")
+			.addIf(password != null, "password")
+			.addIf(clientCredentials != null, "clientCredentials")
+			.addIf(authorizationCode != null, "authorizationCode")
+			.build();
 		return new MultiSet<>(s, super.keySet());
 	}
 
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/OpenApiElement.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/OpenApiElement.java
index 725797b3f..168b85675 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/OpenApiElement.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/OpenApiElement.java
@@ -12,19 +12,18 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
-import org.apache.juneau.ObjectMap;
-import org.apache.juneau.annotation.BeanProperty;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.collections.*;
 import org.apache.juneau.json.JsonSerializer;
-import org.apache.juneau.utils.ASet;
 
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.toBoolean;
-import static org.apache.juneau.internal.BeanPropertyUtils.toType;
-
 /**
  * Root class for all Swagger beans.
  *
@@ -106,7 +105,7 @@ public abstract class OpenApiElement {
 	 * @param property The property name to retrieve.
 	 * @return The property value, or <jk>null</jk> if the property does not exist or is not set.
 	 */
-	@BeanProperty("*")
+	@Beanp("*")
 	public Object get(String property) {
 		if (property == null || extra == null)
 			return null;
@@ -123,7 +122,7 @@ public abstract class OpenApiElement {
 	 * @param value The new value for the property.
 	 * @return This object (for method chaining).
 	 */
-	@BeanProperty("*")
+	@Beanp("*")
 	public OpenApiElement set(String property, Object value) {
 		if (property == null)
 			return this;
@@ -144,9 +143,9 @@ public abstract class OpenApiElement {
 	 * 	All the non-standard keys on this element.
 	 * 	<br>Never <jk>null</jk>.
 	 */
-	@BeanProperty("*")
+	@Beanp("*")
 	public Set<String> extraKeys() {
-		return extra == null ? Collections.EMPTY_SET : extra.keySet();
+		return extra == null ? Collections.emptySet() : extra.keySet();
 	}
 
 	/**
@@ -157,8 +156,9 @@ public abstract class OpenApiElement {
 	 * 	<br>Never <jk>null</jk>.
 	 */
 	public Set<String> keySet() {
-		ASet<String> s = new ASet<String>()
-			.appendIf(strict, "strict");
+		Set<String> s = setBuilder(String.class)
+			.addIf(strict, "strict")
+			.build();
 		s.addAll(extraKeys());
 		return s;
 	}
@@ -171,8 +171,8 @@ public abstract class OpenApiElement {
 	 *
 	 * @return A map containing all the values in this swagger element.
 	 */
-	public ObjectMap asMap() {
-		ObjectMap m = new ObjectMap();
+	public JsonMap asMap() {
+		JsonMap m = new JsonMap();
 		for (String s : keySet())
 			m.put(s, get(s, Object.class));
 		return m;
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/RequestBodyInfo.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/RequestBodyInfo.java
index c605ab7e9..c3f83b7d9 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/RequestBodyInfo.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/RequestBodyInfo.java
@@ -12,262 +12,252 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
 import org.apache.juneau.UriResolver;
 import org.apache.juneau.annotation.Bean;
 import org.apache.juneau.internal.MultiSet;
-import org.apache.juneau.utils.ASet;
 
 import java.net.URI;
 import java.net.URL;
 import java.util.*;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.*;
-
+/**
+ * TODO
+ */
 @Bean(properties="description,content,required,*")
 public class RequestBodyInfo extends OpenApiElement{
 
-    private String description;
-    private Map<String,MediaType> content;
-    private Boolean required;
-
-    /**
-     * Default constructor.
-     */
-    public RequestBodyInfo() { }
-
-    /**
-     * Copy constructor.
-     *
-     * @param copyFrom The object to copy.
-     */
-    public RequestBodyInfo(RequestBodyInfo copyFrom) {
-        super(copyFrom);
-
-        this.description = copyFrom.description;
-        this.required = copyFrom.required;
-        if (copyFrom.content == null) {
-            this.content = null;
-        } else {
-            this.content = new LinkedHashMap<>();
-            for (Map.Entry<String,MediaType> e : copyFrom.content.entrySet())
-                this.content.put(e.getKey(),	e.getValue().copy());
-        }
-    }
+	private String description;
+	private Map<String,MediaType> content;
+	private Boolean required;
 
-    /**
-     * Make a deep copy of this object.
-     *
-     * @return A deep copy of this object.
-     */
-    public RequestBodyInfo copy() {
-        return new RequestBodyInfo(this);
-    }
+	/**
+	 * Default constructor.
+	 */
+	public RequestBodyInfo() { }
 
-    @Override /* OpenApiElement */
-    protected RequestBodyInfo strict() {
-        super.strict();
-        return this;
-    }
+	/**
+	 * Copy constructor.
+	 *
+	 * @param copyFrom The object to copy.
+	 */
+	public RequestBodyInfo(RequestBodyInfo copyFrom) {
+		super(copyFrom);
 
-    /**
-     * Bean property getter:  <property>contentType</property>.
-     *
-     * <p>
-     * The URL pointing to the contact information.
-     *
-     * @return The property value, or <jk>null</jk> if it is not set.
-     */
-    public String getDescription() {
-        return description;
-    }
+		this.description = copyFrom.description;
+		this.required = copyFrom.required;
+		if (copyFrom.content == null) {
+			this.content = null;
+		} else {
+			this.content = new LinkedHashMap<>();
+			for (Map.Entry<String,MediaType> e : copyFrom.content.entrySet())
+				this.content.put(e.getKey(),	e.getValue().copy());
+		}
+	}
 
-    /**
-     * Bean property setter:  <property>url</property>.
-     *
-     * <p>
-     * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}.
-     * <br>Strings must be valid URIs.
-     *
-     * <p>
-     * URIs defined by {@link UriResolver} can be used for values.
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public RequestBodyInfo setDescription(String value) {
-        description = value;
-        return this;
-    }
+	/**
+	 * Make a deep copy of this object.
+	 *
+	 * @return A deep copy of this object.
+	 */
+	public RequestBodyInfo copy() {
+		return new RequestBodyInfo(this);
+	}
 
-    /**
-     * Same as {@link #setDescription(String)}.
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Non-URI values will be converted to URI using <code><jk>new</jk> URI(value.toString())</code>.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public RequestBodyInfo description(Object value) {
-        return setDescription(toStringVal(value));
-    }
+	@Override /* OpenApiElement */
+	protected RequestBodyInfo strict() {
+		super.strict();
+		return this;
+	}
 
-    /**
-     * Bean property getter:  <property>content</property>.
-     */
-    public Map<String, MediaType> getContent() {
-        return content;
-    }
+	/**
+	 * Bean property getter:  <property>contentType</property>.
+	 *
+	 * <p>
+	 * The URL pointing to the contact information.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public String getDescription() {
+		return description;
+	}
 
-    /**
-     * Bean property setter:  <property>content</property>.
-     *
-     * @param value
-     * 	The new value for this property.
-     * @return This object (for method chaining).
-     */
-    public RequestBodyInfo setContent(Map<String, MediaType> value) {
-        content = newMap(value);
-        return this;
-    }
+	/**
+	 * Bean property setter:  <property>url</property>.
+	 *
+	 * <p>
+	 * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}.
+	 * <br>Strings must be valid URIs.
+	 *
+	 * <p>
+	 * URIs defined by {@link UriResolver} can be used for values.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public RequestBodyInfo setDescription(String value) {
+		description = value;
+		return this;
+	}
 
-    /**
-     * Adds one or more values to the <property>content</property> property.
-     *
-     * @param value
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public RequestBodyInfo addContent(Map<String, MediaType> value) {
-        content = addToMap(content,value);
-        return this;
-    }
+	/**
+	 * Same as {@link #setDescription(String)}.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Non-URI values will be converted to URI using <code><jk>new</jk> URI(value.toString())</code>.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public RequestBodyInfo description(Object value) {
+		return setDescription(stringify(value));
+	}
 
-    /**
-     * Adds one or more values to the <property>content</property> property.
-     *
-     * @param value
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public RequestBodyInfo addContent(String keyval, MediaType value) {
-        content = addToMap(content,keyval,value);
-        return this;
-    }
+	/**
+	 * Bean property getter:  <property>content</property>.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public Map<String, MediaType> getContent() {
+		return content;
+	}
 
-    /**
-     * Adds a single value to the <property>content</property> property.
-     *
-     * @param name variable name.
-     * @param value The server variable instance.
-     * @return This object (for method chaining).
-     */
-    public RequestBodyInfo content(String name, MediaType value) {
-        addContent(Collections.singletonMap(name, value));
-        return this;
-    }
+	/**
+	 * Bean property setter:  <property>content</property>.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * @return This object (for method chaining).
+	 */
+	public RequestBodyInfo setContent(Map<String, MediaType> value) {
+		content = copyOf(value);
+		return this;
+	}
 
-    /**
-     * Adds one or more values to the <property>content</property> property.
-     *
-     * @param values
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public RequestBodyInfo content(Object...values) {
-        content = addToMap(content, values, String.class, MediaType.class);
-        return this;
-    }
+	/**
+	 * Adds one or more values to the <property>content</property> property.
+	 *
+	 * @param values
+	 * 	The values to add to this property.
+	 * 	<br>Ignored if <jk>null</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public RequestBodyInfo addContent(Map<String, MediaType> values) {
+		content = mapBuilder(content).sparse().addAll(values).build();
+		return this;
+	}
 
-    public RequestBodyInfo content(Object value) {
-        return setContent((HashMap<String,MediaType>)value);
-    }
+	/**
+	 * Adds one or more values to the <property>content</property> property.
+	 *
+	 * @param key The mapping key.
+	 * @param value
+	 * 	The values to add to this property.
+	 * 	<br>Ignored if <jk>null</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public RequestBodyInfo addContent(String key, MediaType value) {
+		content = mapBuilder(content).sparse().add(key, value).build();
+		return this;
+	}
 
+	/**
+	 * Adds a single value to the <property>content</property> property.
+	 *
+	 * @param name variable name.
+	 * @param value The server variable instance.
+	 * @return This object (for method chaining).
+	 */
+	public RequestBodyInfo content(String name, MediaType value) {
+		addContent(Collections.singletonMap(name, value));
+		return this;
+	}
 
-    /**
-     * Bean property getter:  <property>required</property>.
-     *
-     * <p>
-     * The type of the object.
-     *
-     * @return The property value, or <jk>null</jk> if it is not set.
-     */
-    public Boolean getRequired() {
-        return required;
-    }
+	/**
+	 * Bean property getter:  <property>required</property>.
+	 *
+	 * <p>
+	 * The type of the object.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public Boolean getRequired() {
+		return required;
+	}
 
-    /**
-     * Bean property setter:  <property>explode</property>.
-     *
-     * <p>
-     * The type of the object.
-     *
-     * <h5 class='section'>See Also:</h5>
-     * <ul class='doctree'>
-     * 	<li class='extlink'>{@doc SwaggerDataTypes}
-     * </ul>
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Property value is required.
-     * 	</ul>
-     * @return This object (for method chaining).
-     */
-    public RequestBodyInfo setRequired(Boolean value) {
-        required = value;
-        return this;
-    }
+	/**
+	 * Bean property setter:  <property>explode</property>.
+	 *
+	 * <p>
+	 * The type of the object.
+	 *
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul class='doctree'>
+	 * 	<li class='extlink'>{@doc SwaggerDataTypes}
+	 * </ul>
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Property value is required.
+	 * 	</ul>
+	 * @return This object (for method chaining).
+	 */
+	public RequestBodyInfo setRequired(Boolean value) {
+		required = value;
+		return this;
+	}
 
-    /**
-     * Same as {@link #setRequired(Boolean)}
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Non-String values will be converted to String using <code>toBoolean()</code>.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public RequestBodyInfo required(Object value) {
-        return setRequired(toBoolean(value));
-    }
+	/**
+	 * Same as {@link #setRequired(Boolean)}
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Non-String values will be converted to String using <code>toBoolean()</code>.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public RequestBodyInfo required(Object value) {
+		return setRequired(toBoolean(value));
+	}
 
-    @Override /* OpenApiElement */
-    public <T> T get(String property, Class<T> type) {
-        if (property == null)
-            return null;
-        switch (property) {
-            case "description": return toType(getDescription(), type);
-            case "content": return toType(getContent(), type);
-            case "required": return toType(getRequired(), type);
-            default: return super.get(property, type);
-        }
-    }
+	@Override /* OpenApiElement */
+	public <T> T get(String property, Class<T> type) {
+		if (property == null)
+			return null;
+		switch (property) {
+			case "description": return toType(getDescription(), type);
+			case "content": return toType(getContent(), type);
+			case "required": return toType(getRequired(), type);
+			default: return super.get(property, type);
+		}
+	}
 
-    @Override /* OpenApiElement */
-    public RequestBodyInfo set(String property, Object value) {
-        if (property == null)
-            return this;
-        switch (property) {
-            case "description": return description(value);
-            case "content": return content(value);
-            case "required": return required(value);
-            default:
-                super.set(property, value);
-                return this;
-        }
-    }
+	@Override /* OpenApiElement */
+	public RequestBodyInfo set(String property, Object value) {
+		if (property == null)
+			return this;
+		switch (property) {
+			case "description": return description(value);
+			case "content": return setContent(mapBuilder(String.class,MediaType.class).sparse().addAny(value).build());
+			case "required": return required(value);
+			default:
+				super.set(property, value);
+				return this;
+		}
+	}
 
-    @Override /* OpenApiElement */
-    public Set<String> keySet() {
-        ASet<String> s = new ASet<String>()
-                .appendIf(description != null, "description")
-                .appendIf(content != null, "content")
-                .appendIf(required != null, "required");
-        return new MultiSet<>(s, super.keySet());
-    }
+	@Override /* OpenApiElement */
+	public Set<String> keySet() {
+		Set<String> s = setBuilder(String.class)
+				.addIf(description != null, "description")
+				.addIf(content != null, "content")
+				.addIf(required != null, "required")
+				.build();
+		return new MultiSet<>(s, super.keySet());
+	}
 }
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Response.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Response.java
index 9a070fe0e..543b96369 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Response.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Response.java
@@ -12,382 +12,344 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
 import org.apache.juneau.UriResolver;
 import org.apache.juneau.annotation.Bean;
 import org.apache.juneau.internal.MultiSet;
-import org.apache.juneau.utils.ASet;
 
 import java.net.URI;
 import java.net.URL;
 import java.util.*;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.*;
-
+/**
+ * TODO
+ */
 @Bean(properties="contentType,style,explode,headers,allowReserved,*")
 public class Response extends OpenApiElement{
 
-    private String description;
-    private Map<String,HeaderInfo> headers;
-    private Map<String,MediaType> content;
-    private Map<String,Link> links;
-
-    /**
-     * Default constructor.
-     */
-    public Response() { }
-
-    /**
-     * Copy constructor.
-     *
-     * @param copyFrom The object to copy.
-     */
-    public Response(Response copyFrom) {
-        super(copyFrom);
-
-        this.description = copyFrom.description;
-        if (copyFrom.headers == null) {
-            this.headers = null;
-        } else {
-            this.headers = new LinkedHashMap<>();
-            for (Map.Entry<String,HeaderInfo> e : copyFrom.headers.entrySet())
-                this.headers.put(e.getKey(),	e.getValue().copy());
-        }
-
-        if (copyFrom.content == null) {
-            this.content = null;
-        } else {
-            this.content = new LinkedHashMap<>();
-            for (Map.Entry<String,MediaType> e : copyFrom.content.entrySet())
-                this.content.put(e.getKey(),	e.getValue().copy());
-        }
-
-        if (copyFrom.links == null) {
-            this.links = null;
-        } else {
-            this.links = new LinkedHashMap<>();
-            for (Map.Entry<String,Link> e : copyFrom.links.entrySet())
-                this.links.put(e.getKey(),	e.getValue().copy());
-        }
-    }
-
-    /**
-     * Make a deep copy of this object.
-     *
-     * @return A deep copy of this object.
-     */
-    public Response copy() {
-        return new Response(this);
-    }
-
-    @Override /* OpenApiElement */
-    protected Response strict() {
-        super.strict();
-        return this;
-    }
-
-    /**
-     * Bean property getter:  <property>Description</property>.
-     *
-     * <p>
-     * The URL pointing to the contact information.
-     *
-     * @return The property value, or <jk>null</jk> if it is not set.
-     */
-    public String getDescription() {
-        return description;
-    }
-
-    /**
-     * Bean property setter:  <property>Description</property>.
-     *
-     * <p>
-     * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}.
-     * <br>Strings must be valid URIs.
-     *
-     * <p>
-     * URIs defined by {@link UriResolver} can be used for values.
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public Response setDescription(String value) {
-        description = value;
-        return this;
-    }
-
-    /**
-     * Same as {@link #setDescription(String)} (String)}.
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Non-URI values will be converted to URI using <code><jk>new</jk> URI(value.toString())</code>.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public Response description(Object value) {
-        return setDescription(toStringVal(value));
-    }
-
-    /**
-     * Bean property getter:  <property>headers</property>.
-     */
-    public Map<String, HeaderInfo> getHeaders() {
-        return headers;
-    }
-
-    /**
-     * Bean property setter:  <property>headers</property>.
-     *
-     * @param value
-     * 	The new value for this property.
-     * @return This object (for method chaining).
-     */
-    public Response setHeaders(Map<String, HeaderInfo> value) {
-        headers = newMap(value);
-        return this;
-    }
-
-    /**
-     * Adds one or more values to the <property>headers</property> property.
-     *
-     * @param value
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public Response addHeader(Map<String, HeaderInfo> value) {
-        headers = addToMap(headers,value);
-        return this;
-    }
-
-    /**
-     * Adds one or more values to the <property>variables</property> property.
-     *
-     * @param value
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public Response addHeaders(String keyval, HeaderInfo value) {
-        headers = addToMap(headers,keyval,value);
-        return this;
-    }
-
-    /**
-     * Adds a single value to the <property>headers</property> property.
-     *
-     * @param name variable name.
-     * @param value The server variable instance.
-     * @return This object (for method chaining).
-     */
-    public Response header(String name, HeaderInfo value) {
-        addHeader(Collections.singletonMap(name, value));
-        return this;
-    }
-
-    /**
-     * Adds one or more values to the <property>headers</property> property.
-     *
-     * @param values
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public Response headers(Object...values) {
-        headers = addToMap(headers, values, String.class, HeaderInfo.class);
-        return this;
-    }
-
-    public Response headers(Object value) {
-        return setHeaders((HashMap<String,HeaderInfo>)value);
-    }
-
-    /**
-     * Bean property getter:  <property>headers</property>.
-     */
-    public Map<String, MediaType> getContent() {
-        return content;
-    }
-
-    /**
-     * Bean property setter:  <property>content</property>.
-     *
-     * @param value
-     * 	The new value for this property.
-     * @return This object (for method chaining).
-     */
-    public Response setContent(Map<String, MediaType> value) {
-        content = newMap(value);
-        return this;
-    }
-
-    /**
-     * Adds one or more values to the <property>content</property> property.
-     *
-     * @param value
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public Response addContent(Map<String, MediaType> value) {
-        content = addToMap(content,value);
-        return this;
-    }
-
-    /**
-     * Adds one or more values to the <property>variables</property> property.
-     *
-     * @param value
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public Response addContent(String keyval, MediaType value) {
-        content = addToMap(content,keyval,value);
-        return this;
-    }
-
-    /**
-     * Adds a single value to the <property>headers</property> property.
-     *
-     * @param name variable name.
-     * @param value The server variable instance.
-     * @return This object (for method chaining).
-     */
-    public Response content(String name, MediaType value) {
-        addContent(Collections.singletonMap(name, value));
-        return this;
-    }
-
-    /**
-     * Adds one or more values to the <property>headers</property> property.
-     *
-     * @param values
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public Response content(Object...values) {
-        content = addToMap(content, values, String.class, MediaType.class);
-        return this;
-    }
-
-    public Response content(Object value) {
-        return setContent((HashMap<String,MediaType>)value);
-    }
-
-    /**
-     * Bean property getter:  <property>link</property>.
-     */
-    public Map<String, Link> getLinks() {
-        return links;
-    }
-
-    /**
-     * Bean property setter:  <property>Link</property>.
-     *
-     * @param value
-     * 	The new value for this property.
-     * @return This object (for method chaining).
-     */
-    public Response setLinks(Map<String, Link> value) {
-        links = newMap(value);
-        return this;
-    }
-
-    /**
-     * Adds one or more values to the <property>headers</property> property.
-     *
-     * @param value
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public Response addLink(Map<String, Link> value) {
-        links = addToMap(links,value);
-        return this;
-    }
-
-    /**
-     * Adds one or more values to the <property>variables</property> property.
-     *
-     * @param value
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public Response addLink(String keyval, Link value) {
-        links = addToMap(links,keyval,value);
-        return this;
-    }
-
-    /**
-     * Adds a single value to the <property>headers</property> property.
-     *
-     * @param name variable name.
-     * @param value The server variable instance.
-     * @return This object (for method chaining).
-     */
-    public Response links(String name, Link value) {
-        addLink(Collections.singletonMap(name, value));
-        return this;
-    }
-
-    /**
-     * Adds one or more values to the <property>headers</property> property.
-     *
-     * @param values
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public Response links(Object...values) {
-        links = addToMap(links, values, String.class, Link.class);
-        return this;
-    }
-
-    public Response links(Object value) {
-        return setLinks((HashMap<String,Link>)value);
-    }
-
-
-    @Override /* OpenApiElement */
-    public <T> T get(String property, Class<T> type) {
-        if (property == null)
-            return null;
-        switch (property) {
-            case "description": return toType(getDescription(), type);
-            case "content": return toType(getContent(), type);
-            case "headers": return toType(getHeaders(), type);
-            case "links": return toType(getLinks(), type);
-            default: return super.get(property, type);
-        }
-    }
-
-    @Override /* OpenApiElement */
-    public Response set(String property, Object value) {
-        if (property == null)
-            return this;
-        switch (property) {
-            case "description": return description(value);
-            case "headers": return headers(value);
-            case "content": return content(value);
-            case "links": return links(value);
-            default:
-                super.set(property, value);
-                return this;
-        }
-    }
-
-    @Override /* OpenApiElement */
-    public Set<String> keySet() {
-        ASet<String> s = new ASet<String>()
-                .appendIf(description != null, "description")
-                .appendIf(headers != null, "headers")
-                .appendIf(content != null, "content")
-                .appendIf(links != null, "links");
-        return new MultiSet<>(s, super.keySet());
-    }
+	private String description;
+	private Map<String,HeaderInfo> headers;
+	private Map<String,MediaType> content;
+	private Map<String,Link> links;
+
+	/**
+	 * Default constructor.
+	 */
+	public Response() { }
+
+	/**
+	 * Copy constructor.
+	 *
+	 * @param copyFrom The object to copy.
+	 */
+	public Response(Response copyFrom) {
+		super(copyFrom);
+
+		this.description = copyFrom.description;
+		if (copyFrom.headers == null) {
+			this.headers = null;
+		} else {
+			this.headers = new LinkedHashMap<>();
+			for (Map.Entry<String,HeaderInfo> e : copyFrom.headers.entrySet())
+				this.headers.put(e.getKey(),	e.getValue().copy());
+		}
+
+		if (copyFrom.content == null) {
+			this.content = null;
+		} else {
+			this.content = new LinkedHashMap<>();
+			for (Map.Entry<String,MediaType> e : copyFrom.content.entrySet())
+				this.content.put(e.getKey(),	e.getValue().copy());
+		}
+
+		if (copyFrom.links == null) {
+			this.links = null;
+		} else {
+			this.links = new LinkedHashMap<>();
+			for (Map.Entry<String,Link> e : copyFrom.links.entrySet())
+				this.links.put(e.getKey(),	e.getValue().copy());
+		}
+	}
+
+	/**
+	 * Make a deep copy of this object.
+	 *
+	 * @return A deep copy of this object.
+	 */
+	public Response copy() {
+		return new Response(this);
+	}
+
+	@Override /* OpenApiElement */
+	protected Response strict() {
+		super.strict();
+		return this;
+	}
+
+	/**
+	 * Bean property getter:  <property>Description</property>.
+	 *
+	 * <p>
+	 * The URL pointing to the contact information.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public String getDescription() {
+		return description;
+	}
+
+	/**
+	 * Bean property setter:  <property>Description</property>.
+	 *
+	 * <p>
+	 * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}.
+	 * <br>Strings must be valid URIs.
+	 *
+	 * <p>
+	 * URIs defined by {@link UriResolver} can be used for values.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public Response setDescription(String value) {
+		description = value;
+		return this;
+	}
+
+	/**
+	 * Same as {@link #setDescription(String)} (String)}.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Non-URI values will be converted to URI using <code><jk>new</jk> URI(value.toString())</code>.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public Response description(Object value) {
+		return setDescription(stringify(value));
+	}
+
+	/**
+	 * Bean property getter:  <property>headers</property>.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public Map<String, HeaderInfo> getHeaders() {
+		return headers;
+	}
+
+	/**
+	 * Bean property setter:  <property>headers</property>.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * @return This object (for method chaining).
+	 */
+	public Response setHeaders(Map<String, HeaderInfo> value) {
+		headers = copyOf(value);
+		return this;
+	}
+
+	/**
+	 * Adds one or more values to the <property>headers</property> property.
+	 *
+	 * @param values
+	 * 	The values to add to this property.
+	 * 	<br>Ignored if <jk>null</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public Response addHeader(Map<String, HeaderInfo> values) {
+		headers = mapBuilder(headers).sparse().addAll(values).build();
+		return this;
+	}
+
+	/**
+	 * Adds one or more values to the <property>variables</property> property.
+	 *
+	 * @param key The mapping key.
+	 * @param value
+	 * 	The values to add to this property.
+	 * 	<br>Ignored if <jk>null</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public Response addHeaders(String key, HeaderInfo value) {
+		headers = mapBuilder(headers).sparse().add(key, value).build();
+		return this;
+	}
+
+	/**
+	 * Adds a single value to the <property>headers</property> property.
+	 *
+	 * @param name variable name.
+	 * @param value The server variable instance.
+	 * @return This object (for method chaining).
+	 */
+	public Response header(String name, HeaderInfo value) {
+		addHeader(Collections.singletonMap(name, value));
+		return this;
+	}
+
+	/**
+	 * Bean property getter:  <property>headers</property>.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public Map<String, MediaType> getContent() {
+		return content;
+	}
+
+	/**
+	 * Bean property setter:  <property>content</property>.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * @return This object (for method chaining).
+	 */
+	public Response setContent(Map<String, MediaType> value) {
+		content = copyOf(value);
+		return this;
+	}
+
+	/**
+	 * Adds one or more values to the <property>content</property> property.
+	 *
+	 * @param values
+	 * 	The values to add to this property.
+	 * 	<br>Ignored if <jk>null</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public Response addContent(Map<String, MediaType> values) {
+		content = mapBuilder(content).sparse().addAll(values).build();
+		return this;
+	}
+
+	/**
+	 * Adds one or more values to the <property>variables</property> property.
+	 *
+	 * @param key The mapping key.
+	 * @param value
+	 * 	The values to add to this property.
+	 * 	<br>Ignored if <jk>null</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public Response addContent(String key, MediaType value) {
+		content = mapBuilder(content).sparse().add(key, value).build();
+		return this;
+	}
+
+	/**
+	 * Adds a single value to the <property>headers</property> property.
+	 *
+	 * @param name variable name.
+	 * @param value The server variable instance.
+	 * @return This object (for method chaining).
+	 */
+	public Response content(String name, MediaType value) {
+		addContent(Collections.singletonMap(name, value));
+		return this;
+	}
+
+	/**
+	 * Bean property getter:  <property>link</property>.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public Map<String, Link> getLinks() {
+		return links;
+	}
+
+	/**
+	 * Bean property setter:  <property>Link</property>.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * @return This object (for method chaining).
+	 */
+	public Response setLinks(Map<String, Link> value) {
+		links = copyOf(value);
+		return this;
+	}
+
+	/**
+	 * Adds one or more values to the <property>headers</property> property.
+	 *
+	 * @param values
+	 * 	The values to add to this property.
+	 * 	<br>Ignored if <jk>null</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public Response addLink(Map<String, Link> values) {
+		links = mapBuilder(links).sparse().addAll(values).build();
+		return this;
+	}
+
+	/**
+	 * Adds one or more values to the <property>variables</property> property.
+	 *
+	 * @param key The mapping key.
+	 * @param value
+	 * 	The values to add to this property.
+	 * 	<br>Ignored if <jk>null</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public Response addLink(String key, Link value) {
+		links = mapBuilder(links).sparse().add(key, value).build();
+		return this;
+	}
+
+	/**
+	 * Adds a single value to the <property>headers</property> property.
+	 *
+	 * @param name variable name.
+	 * @param value The server variable instance.
+	 * @return This object (for method chaining).
+	 */
+	public Response links(String name, Link value) {
+		addLink(Collections.singletonMap(name, value));
+		return this;
+	}
+
+	@Override /* OpenApiElement */
+	public <T> T get(String property, Class<T> type) {
+		if (property == null)
+			return null;
+		switch (property) {
+			case "description": return toType(getDescription(), type);
+			case "content": return toType(getContent(), type);
+			case "headers": return toType(getHeaders(), type);
+			case "links": return toType(getLinks(), type);
+			default: return super.get(property, type);
+		}
+	}
+
+	@Override /* OpenApiElement */
+	public Response set(String property, Object value) {
+		if (property == null)
+			return this;
+		switch (property) {
+			case "description": return description(value);
+			case "headers": return setHeaders(mapBuilder(String.class,HeaderInfo.class).sparse().addAny(value).build());
+			case "content": return setContent(mapBuilder(String.class,MediaType.class).sparse().addAny(value).build());
+			case "links": return setLinks(mapBuilder(String.class,Link.class).sparse().addAny(value).build());
+			default:
+				super.set(property, value);
+				return this;
+		}
+	}
+
+	@Override /* OpenApiElement */
+	public Set<String> keySet() {
+		Set<String> s = setBuilder(String.class)
+				.addIf(description != null, "description")
+				.addIf(headers != null, "headers")
+				.addIf(content != null, "content")
+				.addIf(links != null, "links")
+				.build();
+		return new MultiSet<>(s, super.keySet());
+	}
 }
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/SchemaInfo.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/SchemaInfo.java
index 4e6f38a32..07fa8755d 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/SchemaInfo.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/SchemaInfo.java
@@ -12,19 +12,17 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
-import org.apache.juneau.annotation.Bean;
-import org.apache.juneau.annotation.BeanProperty;
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
 import org.apache.juneau.dto.swagger.ExternalDocumentation;
+import org.apache.juneau.annotation.*;
 import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.dto.swagger.Xml;
 import org.apache.juneau.internal.MultiSet;
-import org.apache.juneau.internal.StringUtils;
-import org.apache.juneau.utils.ASet;
-
 import java.util.*;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.*;
-
 /**
  * The Schema Object allows the definition of input and output data types.
  *
@@ -151,11 +149,11 @@ public class SchemaInfo extends OpenApiElement {
 		this.items = copyFrom.items == null ? null : copyFrom.items.copy();
 		this.xml = copyFrom.xml == null ? null : copyFrom.xml.copy();
 		this.externalDocs = copyFrom.externalDocs == null ? null : copyFrom.externalDocs.copy();
-		this._enum = newList(copyFrom._enum);
-		this.allOf = newList(copyFrom.allOf);
-		this.required = newList(copyFrom.required);
-		this.anyOf = newList(copyFrom.anyOf);
-		this.oneOf = newList(copyFrom.oneOf);
+		this._enum = copyOf(copyFrom._enum);
+		this.allOf = copyOf(copyFrom.allOf);
+		this.required = copyOf(copyFrom.required);
+		this.anyOf = copyOf(copyFrom.anyOf);
+		this.oneOf = copyOf(copyFrom.oneOf);
 
 		if (copyFrom.properties == null) {
 			this.properties = null;
@@ -232,7 +230,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo format(Object value) {
-		return setFormat(toStringVal(value));
+		return setFormat(stringify(value));
 	}
 
 	/**
@@ -267,7 +265,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo title(Object value) {
-		return setTitle(toStringVal(value));
+		return setTitle(stringify(value));
 	}
 
 	/**
@@ -303,7 +301,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo description(Object value) {
-		return setDescription(toStringVal(value));
+		return setDescription(stringify(value));
 	}
 
 	/**
@@ -624,7 +622,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo pattern(Object value) {
-		return setPattern(toStringVal(value));
+		return setPattern(stringify(value));
 	}
 
 	/**
@@ -866,7 +864,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo setRequired(Collection<String> value) {
-		required = newList(value);
+		required = listFrom(value);
 		return this;
 	}
 
@@ -882,7 +880,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo addRequired(Collection<String> value) {
-		required = addToList(required, value);
+		required = listBuilder(required).sparse().addAny(value).build();
 		return this;
 	}
 
@@ -907,8 +905,8 @@ public class SchemaInfo extends OpenApiElement {
 	 * 	</ul>
 	 * @return This object (for method chaining).
 	 */
-	public SchemaInfo required(Object...values) {
-		required = addToList(required, values, String.class);
+	public SchemaInfo required(String...values) {
+		required = listBuilder(String.class).sparse().add(values).build();
 		return this;
 	}
 
@@ -935,7 +933,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo setEnum(Collection<Object> value) {
-		_enum = newList(value);
+		_enum = listFrom(value);
 		return this;
 	}
 
@@ -948,7 +946,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo addEnum(Collection<Object> value) {
-		_enum = addToList(_enum, value);
+		_enum = listBuilder(_enum).sparse().addAny(value).build();
 		return this;
 	}
 
@@ -976,7 +974,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo _enum(Object...values) {
-		_enum = addToList(_enum, values, Object.class);
+		setEnum(setBuilder(Object.class).sparse().addAny(values).build());
 		return this;
 	}
 
@@ -1027,7 +1025,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo type(Object value) {
-		return setType(toStringVal(value));
+		return setType(stringify(value));
 	}
 
 	/**
@@ -1091,7 +1089,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo setAllOf(Collection<Object> value) {
-		allOf = newList(value);
+		allOf = listFrom(value);
 		return this;
 	}
 
@@ -1104,7 +1102,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo addAllOf(Collection<Object> values) {
-		allOf = addToList(allOf, values);
+		allOf = listBuilder(allOf).sparse().addAny(values).build();
 		return this;
 	}
 
@@ -1132,7 +1130,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo allOf(Object...values) {
-		allOf = addToList(allOf, values, Object.class);
+		allOf = listBuilder(allOf).sparse().addAny(values).build();
 		return this;
 	}
 
@@ -1154,7 +1152,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo setAnyOf(Collection<Object> value) {
-		anyOf = newList(value);
+		anyOf = listFrom(value);
 		return this;
 	}
 
@@ -1167,7 +1165,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo addAnyOf(Collection<Object> values) {
-		anyOf = addToList(anyOf, values);
+		anyOf = listBuilder(anyOf).sparse().addAny(values).build();
 		return this;
 	}
 
@@ -1195,7 +1193,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo anyOf(Object...values) {
-		anyOf = addToList(anyOf, values, Object.class);
+		anyOf = listBuilder(anyOf).sparse().addAny(values).build();
 		return this;
 	}
 
@@ -1215,7 +1213,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo setOneOf(Collection<Object> value) {
-		oneOf = newList(value);
+		oneOf = listFrom(value);
 		return this;
 	}
 
@@ -1228,7 +1226,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo addOneOf(Collection<Object> values) {
-		oneOf = addToList(oneOf, values);
+		oneOf = listBuilder(oneOf).sparse().addAny(values).build();
 		return this;
 	}
 
@@ -1256,7 +1254,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo oneOf(Object...values) {
-		oneOf = addToList(oneOf, values, Object.class);
+		oneOf = listBuilder(oneOf).sparse().addAny(values).build();
 		return this;
 	}
 
@@ -1278,7 +1276,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo setProperties(Map<String, SchemaInfo> value) {
-		properties = newMap(value);
+		properties = copyOf(value);
 		return this;
 	}
 
@@ -1291,29 +1289,7 @@ public class SchemaInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SchemaInfo addProperties(Map<String, SchemaInfo> values) {
-		properties = addToMap(properties, values);
-		return this;
-	}
-
-	/**
-	 * Adds one or more values to the <property>properties</property> property.
-	 *
-	 * @param values
-	 * 	The values to add to this property.
-	 * 	<br>Valid types:
-	 * 	<ul>
-	 * 		<li><code>Map&lt;String,Map&lt;String,Object&gt;&gt;</code>
-	 * 		<li><code>String</code> - JSON object representation of <code>Map&lt;String,Map&lt;String,Object&gt;&gt;</code>
-	 * 			<h5 class='figure'>Example:</h5>
-	 * 			<p class='bcode w800'>
-	 * 	properties(<js>"{name:{foo:'bar'}}"</js>);
-	 * 			</p>
-	 * 	</ul>
-	 * 	<br>Ignored if <jk>null</jk>.
-	 * @return This object (for method chaining).
-	 */
-	public SchemaInfo properties(Object...values) {
-		properties = addToMap(properties, values, String.class, SchemaInfo.class);
+		properties = mapBuilder(properties).sparse().addAll(values).build();
 		return this;
 	}
 
@@ -1653,7 +1629,7 @@ public class SchemaInfo extends OpenApiElement {
 	 *
 	 * @return The property value, or <jk>null</jk> if it is not set.
 	 */
-	@BeanProperty("$ref")
+	@Beanp("$ref")
 	public String getRef() {
 		return ref;
 	}
@@ -1675,9 +1651,9 @@ public class SchemaInfo extends OpenApiElement {
 	 * 	<br>Can be <jk>null</jk> to unset the property.
 	 * @return This object (for method chaining).
 	 */
-	@BeanProperty("$ref")
+	@Beanp("$ref")
 	public SchemaInfo setRef(Object value) {
-		ref = StringUtils.asString(value);
+		ref = stringify(value);
 		return this;
 	}
 
@@ -1760,14 +1736,14 @@ public class SchemaInfo extends OpenApiElement {
 			case "uniqueItems": return uniqueItems(value);
 			case "maxProperties": return maxProperties(value);
 			case "minProperties": return minProperties(value);
-			case "required": return setRequired(null).required(value);
+			case "required": return setRequired(null).required(stringify(value));
 			case "enum": return setEnum(null)._enum(value);
 			case "type": return type(value);
 			case "items": return items(value);
 			case "allOf": return setAllOf(null).allOf(value);
 			case "anyOf": return setAnyOf(null).anyOf(value);
 			case "oneOf": return setOneOf(null).oneOf(value);
-			case "properties": return setProperties(null).properties(value);
+			case "properties": return setProperties(mapBuilder(String.class,SchemaInfo.class).sparse().addAny(value).build());
 			case "additionalProperties": return additionalProperties(value);
 			case "not": return not(value);
 			case "nullable": return nullable(value);
@@ -1787,43 +1763,44 @@ public class SchemaInfo extends OpenApiElement {
 
 	@Override /* SwaggerElement */
 	public Set<String> keySet() {
-		ASet<String> s = new ASet<String>()
-			.appendIf(format != null, "format")
-			.appendIf(title != null, "title")
-			.appendIf(description != null, "description")
-			.appendIf(_default != null, "default")
-			.appendIf(multipleOf != null, "multipleOf")
-			.appendIf(maximum != null, "maximum")
-			.appendIf(exclusiveMaximum != null, "exclusiveMaximum")
-			.appendIf(minimum != null, "minimum")
-			.appendIf(exclusiveMinimum != null, "exclusiveMinimum")
-			.appendIf(maxLength != null, "maxLength")
-			.appendIf(minLength != null, "minLength")
-			.appendIf(pattern != null, "pattern")
-			.appendIf(maxItems != null, "maxItems")
-			.appendIf(minItems != null, "minItems")
-			.appendIf(uniqueItems != null, "uniqueItems")
-			.appendIf(maxProperties != null, "maxProperties")
-			.appendIf(minProperties != null, "minProperties")
-			.appendIf(required != null, "required")
-			.appendIf(_enum != null, "enum")
-			.appendIf(type != null, "type")
-			.appendIf(items != null, "items")
-			.appendIf(allOf != null, "allOf")
-			.appendIf(anyOf != null, "anyOf")
-			.appendIf(oneOf != null, "oneOf")
-			.appendIf(properties != null, "properties")
-			.appendIf(additionalProperties != null, "additionalProperties")
-			.appendIf(nullable != null, "nullable")
-			.appendIf(deprecated != null, "deprecated")
-			.appendIf(not != null, "not")
-			.appendIf(discriminator != null, "discriminator")
-			.appendIf(readOnly != null, "readOnly")
-			.appendIf(writeOnly != null, "writeOnly")
-			.appendIf(xml != null, "xml")
-			.appendIf(externalDocs != null, "externalDocs")
-			.appendIf(example != null, "example")
-			.appendIf(ref != null, "$ref");
+		Set<String> s = setBuilder(String.class)
+			.addIf(format != null, "format")
+			.addIf(title != null, "title")
+			.addIf(description != null, "description")
+			.addIf(_default != null, "default")
+			.addIf(multipleOf != null, "multipleOf")
+			.addIf(maximum != null, "maximum")
+			.addIf(exclusiveMaximum != null, "exclusiveMaximum")
+			.addIf(minimum != null, "minimum")
+			.addIf(exclusiveMinimum != null, "exclusiveMinimum")
+			.addIf(maxLength != null, "maxLength")
+			.addIf(minLength != null, "minLength")
+			.addIf(pattern != null, "pattern")
+			.addIf(maxItems != null, "maxItems")
+			.addIf(minItems != null, "minItems")
+			.addIf(uniqueItems != null, "uniqueItems")
+			.addIf(maxProperties != null, "maxProperties")
+			.addIf(minProperties != null, "minProperties")
+			.addIf(required != null, "required")
+			.addIf(_enum != null, "enum")
+			.addIf(type != null, "type")
+			.addIf(items != null, "items")
+			.addIf(allOf != null, "allOf")
+			.addIf(anyOf != null, "anyOf")
+			.addIf(oneOf != null, "oneOf")
+			.addIf(properties != null, "properties")
+			.addIf(additionalProperties != null, "additionalProperties")
+			.addIf(nullable != null, "nullable")
+			.addIf(deprecated != null, "deprecated")
+			.addIf(not != null, "not")
+			.addIf(discriminator != null, "discriminator")
+			.addIf(readOnly != null, "readOnly")
+			.addIf(writeOnly != null, "writeOnly")
+			.addIf(xml != null, "xml")
+			.addIf(externalDocs != null, "externalDocs")
+			.addIf(example != null, "example")
+			.addIf(ref != null, "$ref")
+			.build();
 		return new MultiSet<>(s, super.keySet());
 	}
 
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/SecuritySchemeInfo.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/SecuritySchemeInfo.java
index 980486d4f..117c7cf0e 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/SecuritySchemeInfo.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/SecuritySchemeInfo.java
@@ -12,18 +12,19 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
-import org.apache.juneau.FormattedRuntimeException;
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
+import org.apache.juneau.*;
 import org.apache.juneau.annotation.Bean;
 import org.apache.juneau.dto.swagger.Items;
 import org.apache.juneau.dto.swagger.SchemaInfo;
-import org.apache.juneau.dto.swagger.Swagger;
 import org.apache.juneau.internal.MultiSet;
-import org.apache.juneau.utils.ASet;
 
 import java.util.*;
 
 import static org.apache.juneau.internal.ArrayUtils.contains;
-import static org.apache.juneau.internal.BeanPropertyUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
 
 /**
  * Describes a single operation parameter.
@@ -219,7 +220,7 @@ public class SecuritySchemeInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SecuritySchemeInfo name(Object value) {
-		return setName(toStringVal(value));
+		return setName(stringify(value));
 	}
 
 	/**
@@ -255,10 +256,10 @@ public class SecuritySchemeInfo extends OpenApiElement {
 	 */
 	public SecuritySchemeInfo setIn(String value) {
 		if (isStrict() && ! contains(value, VALID_IN))
-			throw new FormattedRuntimeException(
+			throw BasicRuntimeException.create().message(
 				"Invalid value passed in to setIn(String).  Value=''{0}'', valid values={1}",
 				value, VALID_IN
-			);
+			).build();
 		in = value;
 		return this;
 	}
@@ -281,7 +282,7 @@ public class SecuritySchemeInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SecuritySchemeInfo in(Object value) {
-		return setIn(toStringVal(value));
+		return setIn(stringify(value));
 	}
 
 	/**
@@ -326,7 +327,7 @@ public class SecuritySchemeInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SecuritySchemeInfo description(Object value) {
-		return setDescription(toStringVal(value));
+		return setDescription(stringify(value));
 	}
 
 	/**
@@ -375,7 +376,7 @@ public class SecuritySchemeInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SecuritySchemeInfo scheme(Object value) {
-		return setScheme(toStringVal(value));
+		return setScheme(stringify(value));
 	}
 
 	/**
@@ -419,10 +420,10 @@ public class SecuritySchemeInfo extends OpenApiElement {
 	 */
 	public SecuritySchemeInfo setType(String value) {
 		if (isStrict() && ! contains(value, VALID_TYPES))
-			throw new FormattedRuntimeException(
+			throw BasicRuntimeException.create().message(
 				"Invalid value passed in to setType(String).  Value=''{0}'', valid values={1}",
 				value, VALID_TYPES
-			);
+			).build();
 		type = value;
 		return this;
 	}
@@ -448,7 +449,7 @@ public class SecuritySchemeInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SecuritySchemeInfo type(Object value) {
-		return setType(toStringVal(value));
+		return setType(stringify(value));
 	}
 
 	/**
@@ -497,7 +498,7 @@ public class SecuritySchemeInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SecuritySchemeInfo bearerFormat(Object value) {
-		return setBearerFormat(toStringVal(value));
+		return setBearerFormat(stringify(value));
 	}
 
 	/**
@@ -588,7 +589,7 @@ public class SecuritySchemeInfo extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public SecuritySchemeInfo openIdConnectUrl(Object value) {
-		return setOpenIdConnectUrl(toStringVal(value));
+		return setOpenIdConnectUrl(stringify(value));
 	}
 
 	@Override /* SwaggerElement */
@@ -629,15 +630,16 @@ public class SecuritySchemeInfo extends OpenApiElement {
 
 	@Override /* SwaggerElement */
 	public Set<String> keySet() {
-		ASet<String> s = new ASet<String>()
-			.appendIf(name != null, "name")
-			.appendIf(in != null, "in")
-			.appendIf(description != null, "description")
-			.appendIf(scheme != null, "scheme")
-			.appendIf(bearerFormat != null, "bearerFormat")
-			.appendIf(type != null, "type")
-			.appendIf(flows != null, "flows")
-			.appendIf(openIdConnectUrl != null, "openIdConnectUrl");
+		Set<String> s = setBuilder(String.class)
+			.addIf(name != null, "name")
+			.addIf(in != null, "in")
+			.addIf(description != null, "description")
+			.addIf(scheme != null, "scheme")
+			.addIf(bearerFormat != null, "bearerFormat")
+			.addIf(type != null, "type")
+			.addIf(flows != null, "flows")
+			.addIf(openIdConnectUrl != null, "openIdConnectUrl")
+			.build();
 		return new MultiSet<>(s, super.keySet());
 	}
 
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Server.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Server.java
index 8749099f8..c42a78d70 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Server.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Server.java
@@ -12,246 +12,237 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
 import org.apache.juneau.UriResolver;
 import org.apache.juneau.annotation.Bean;
-import org.apache.juneau.dto.swagger.Contact;
-import org.apache.juneau.dto.swagger.HeaderInfo;
 import org.apache.juneau.internal.MultiSet;
 import org.apache.juneau.internal.StringUtils;
-import org.apache.juneau.utils.ASet;
 
 import java.net.URI;
 import java.net.URL;
 import java.util.*;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.*;
-
+/**
+ * TODO
+ */
 @Bean(properties="url,description,variables,*")
 public class Server extends OpenApiElement{
-    private URI url;
-    private String description;
-    private Map<String,ServerVariable> variables;
-
-    /**
-     * Default constructor.
-     */
-    public Server() { }
-
-    /**
-     * Copy constructor.
-     *
-     * @param copyFrom The object to copy.
-     */
-    public Server(Server copyFrom) {
-        super(copyFrom);
-
-        this.url = copyFrom.url;
-        this.description = copyFrom.description;
-        if (copyFrom.variables == null) {
-            this.variables = null;
-        } else {
-            this.variables = new LinkedHashMap<>();
-            for (Map.Entry<String,ServerVariable> e : copyFrom.variables.entrySet())
-                this.variables.put(e.getKey(),	e.getValue().copy());
-        }
-    }
-
-    /**
-     * Make a deep copy of this object.
-     *
-     * @return A deep copy of this object.
-     */
-    public Server copy() {
-        return new Server(this);
-    }
-
-    @Override /* OpenApiElement */
-    protected Server strict() {
-        super.strict();
-        return this;
-    }
-
-    /**
-     * Bean property getter:  <property>url</property>.
-     *
-     * <p>
-     * The URL pointing to the contact information.
-     *
-     * @return The property value, or <jk>null</jk> if it is not set.
-     */
-    public URI getUrl() {
-        return url;
-    }
-
-    /**
-     * Bean property setter:  <property>url</property>.
-     *
-     * <p>
-     * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}.
-     * <br>Strings must be valid URIs.
-     *
-     * <p>
-     * URIs defined by {@link UriResolver} can be used for values.
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public Server setUrl(URI value) {
-        url = value;
-        return this;
-    }
-
-    /**
-     * Same as {@link #setUrl(URI)}.
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Non-URI values will be converted to URI using <code><jk>new</jk> URI(value.toString())</code>.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public Server url(Object value) {
-        return setUrl(StringUtils.toURI(value));
-    }
-
-    /**
-     * Bean property getter:  <property>description</property>.
-     */
-    public String getDescription() {
-        return description;
-    }
-
-    /**
-     * Bean property setter:  <property>description</property>.
-     *
-     * @param value
-     * 	The new value for this property.
-     * @return This object (for method chaining).
-     */
-    public Server setDescription(String value) {
-        description = value;
-        return this;
-    }
-
-    /**
-     * Same as {@link #setDescription(String)}.
-     *
-     * @param value
-     * 	The new value for this property.
-     * @return This object (for method chaining).
-     */
-    public Server description(Object value) {
-        return setDescription(toStringVal(value));
-    }
-
-    /**
-     * Bean property getter:  <property>variables</property>.
-     */
-    public Map<String, ServerVariable> getVariables() {
-        return variables;
-    }
-
-    /**
-     * Bean property setter:  <property>variables</property>.
-     *
-     * @param value
-     * 	The new value for this property.
-     * @return This object (for method chaining).
-     */
-    public Server setVariables(Map<String, ServerVariable> value) {
-        variables = newMap(value);
-        return this;
-    }
-
-    /**
-     * Adds one or more values to the <property>variables</property> property.
-     *
-     * @param value
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public Server addVariables(Map<String, ServerVariable> value) {
-        variables = addToMap(variables,value);
-        return this;
-    }
-
-    /**
-     * Adds one or more values to the <property>variables</property> property.
-     *
-     * @param value
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public Server addVariables(String keyval, ServerVariable value) {
-        variables = addToMap(variables,keyval,value);
-        return this;
-    }
-
-    /**
-     * Adds a single value to the <property>headers</property> property.
-     *
-     * @param name variable name.
-     * @param value The server variable instance.
-     * @return This object (for method chaining).
-     */
-    public Server variable(String name, ServerVariable value) {
-        addVariables(Collections.singletonMap(name, value));
-        return this;
-    }
-
-    /**
-     * Adds one or more values to the <property>variables</property> property.
-     *
-     * @param values
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public Server headers(Object...values) {
-        variables = addToMap(variables, values, String.class, ServerVariable.class);
-        return this;
-    }
-
-    public Server variables(Object value) {
-        return setVariables((HashMap<String,ServerVariable>)value);
-    }
-
-    @Override /* OpenApiElement */
-    public <T> T get(String property, Class<T> type) {
-        if (property == null)
-            return null;
-        switch (property) {
-            case "url": return toType(getUrl(), type);
-            case "description": return toType(getDescription(), type);
-            case "variables": return toType(getVariables(), type);
-            default: return super.get(property, type);
-        }
-    }
-
-    @Override /* OpenApiElement */
-    public Server set(String property, Object value) {
-        if (property == null)
-            return this;
-        switch (property) {
-            case "url": return url(value);
-            case "description": return description(value);
-            case "variables": return variables(value);
-            default:
-                super.set(property, value);
-                return this;
-        }
-    }
-
-    @Override /* OpenApiElement */
-    public Set<String> keySet() {
-        ASet<String> s = new ASet<String>()
-                .appendIf(url != null, "url")
-                .appendIf(description != null, "description")
-                .appendIf(variables != null, "variables");
-        return new MultiSet<>(s, super.keySet());
-    }
+	private URI url;
+	private String description;
+	private Map<String,ServerVariable> variables;
+
+	/**
+	 * Default constructor.
+	 */
+	public Server() { }
+
+	/**
+	 * Copy constructor.
+	 *
+	 * @param copyFrom The object to copy.
+	 */
+	public Server(Server copyFrom) {
+		super(copyFrom);
+
+		this.url = copyFrom.url;
+		this.description = copyFrom.description;
+		if (copyFrom.variables == null) {
+			this.variables = null;
+		} else {
+			this.variables = new LinkedHashMap<>();
+			for (Map.Entry<String,ServerVariable> e : copyFrom.variables.entrySet())
+				this.variables.put(e.getKey(),	e.getValue().copy());
+		}
+	}
+
+	/**
+	 * Make a deep copy of this object.
+	 *
+	 * @return A deep copy of this object.
+	 */
+	public Server copy() {
+		return new Server(this);
+	}
+
+	@Override /* OpenApiElement */
+	protected Server strict() {
+		super.strict();
+		return this;
+	}
+
+	/**
+	 * Bean property getter:  <property>url</property>.
+	 *
+	 * <p>
+	 * The URL pointing to the contact information.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public URI getUrl() {
+		return url;
+	}
+
+	/**
+	 * Bean property setter:  <property>url</property>.
+	 *
+	 * <p>
+	 * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}.
+	 * <br>Strings must be valid URIs.
+	 *
+	 * <p>
+	 * URIs defined by {@link UriResolver} can be used for values.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public Server setUrl(URI value) {
+		url = value;
+		return this;
+	}
+
+	/**
+	 * Same as {@link #setUrl(URI)}.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Non-URI values will be converted to URI using <code><jk>new</jk> URI(value.toString())</code>.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public Server url(Object value) {
+		return setUrl(StringUtils.toURI(value));
+	}
+
+	/**
+	 * Bean property getter:  <property>description</property>.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public String getDescription() {
+		return description;
+	}
+
+	/**
+	 * Bean property setter:  <property>description</property>.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * @return This object (for method chaining).
+	 */
+	public Server setDescription(String value) {
+		description = value;
+		return this;
+	}
+
+	/**
+	 * Same as {@link #setDescription(String)}.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * @return This object (for method chaining).
+	 */
+	public Server description(Object value) {
+		return setDescription(stringify(value));
+	}
+
+	/**
+	 * Bean property getter:  <property>variables</property>.
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public Map<String, ServerVariable> getVariables() {
+		return variables;
+	}
+
+	/**
+	 * Bean property setter:  <property>variables</property>.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * @return This object (for method chaining).
+	 */
+	public Server setVariables(Map<String, ServerVariable> value) {
+		variables = copyOf(value);
+		return this;
+	}
+
+	/**
+	 * Adds one or more values to the <property>variables</property> property.
+	 *
+	 * @param values
+	 * 	The values to add to this property.
+	 * 	<br>Ignored if <jk>null</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public Server addVariables(Map<String, ServerVariable> values) {
+		variables = mapBuilder(variables).sparse().addAll(values).build();
+		return this;
+	}
+
+	/**
+	 * Adds one or more values to the <property>variables</property> property.
+	 *
+	 * @param key The mapping key.
+	 * @param value
+	 * 	The values to add to this property.
+	 * 	<br>Ignored if <jk>null</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public Server addVariables(String key, ServerVariable value) {
+		variables = mapBuilder(variables).sparse().add(key, value).build();
+		return this;
+	}
+
+	/**
+	 * Adds a single value to the <property>headers</property> property.
+	 *
+	 * @param name variable name.
+	 * @param value The server variable instance.
+	 * @return This object (for method chaining).
+	 */
+	public Server variable(String name, ServerVariable value) {
+		addVariables(Collections.singletonMap(name, value));
+		return this;
+	}
+
+	@Override /* OpenApiElement */
+	public <T> T get(String property, Class<T> type) {
+		if (property == null)
+			return null;
+		switch (property) {
+			case "url": return toType(getUrl(), type);
+			case "description": return toType(getDescription(), type);
+			case "variables": return toType(getVariables(), type);
+			default: return super.get(property, type);
+		}
+	}
+
+	@Override /* OpenApiElement */
+	public Server set(String property, Object value) {
+		if (property == null)
+			return this;
+		switch (property) {
+			case "url": return url(value);
+			case "description": return description(value);
+			case "variables": return setVariables(mapBuilder(String.class,ServerVariable.class).sparse().addAny(value).build());
+			default:
+				super.set(property, value);
+				return this;
+		}
+	}
+
+	@Override /* OpenApiElement */
+	public Set<String> keySet() {
+		Set<String> s = setBuilder(String.class)
+				.addIf(url != null, "url")
+				.addIf(description != null, "description")
+				.addIf(variables != null, "variables")
+				.build();
+		return new MultiSet<>(s, super.keySet());
+	}
 }
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/ServerVariable.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/ServerVariable.java
index fd7bcc301..7bcc89370 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/ServerVariable.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/ServerVariable.java
@@ -12,302 +12,306 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
 import org.apache.juneau.annotation.Bean;
-import org.apache.juneau.dto.swagger.Items;
 import org.apache.juneau.internal.MultiSet;
-import org.apache.juneau.utils.ASet;
 
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.*;
-
-
+/**
+ * TODO
+ */
 @Bean(properties="enum,default,description,*")
 public class ServerVariable extends OpenApiElement {
 
-    private List<Object> _enum;
-    private String _default;
-    private String description;
+	private List<Object> _enum;
+	private String _default;
+	private String description;
 
-    /**
-     * Default constructor.
-     */
-    public ServerVariable() {}
+	/**
+	 * Default constructor.
+	 */
+	public ServerVariable() {}
 
-    /**
-     * Copy constructor.
-     *
-     * @param copyFrom The object to copy.
-     */
-    public ServerVariable(ServerVariable copyFrom) {
-        super(copyFrom);
+	/**
+	 * Copy constructor.
+	 *
+	 * @param copyFrom The object to copy.
+	 */
+	public ServerVariable(ServerVariable copyFrom) {
+		super(copyFrom);
 
-        this._enum = newList(copyFrom._enum);
-        this._default = copyFrom._default;
-        this.description = copyFrom.description;
-    }
+		this._enum = copyOf(copyFrom._enum);
+		this._default = copyFrom._default;
+		this.description = copyFrom.description;
+	}
 
-    /**
-     * Make a deep copy of this object.
-     * @return A deep copy of this object.
-     */
-    public ServerVariable copy() {
-        return new ServerVariable(this);
-    }
+	/**
+	 * Make a deep copy of this object.
+	 * @return A deep copy of this object.
+	 */
+	public ServerVariable copy() {
+		return new ServerVariable(this);
+	}
 
-    @Override /* OpenApiElement */
-    protected ServerVariable strict() {
-        super.strict();
-        return this;
-    }
+	@Override /* OpenApiElement */
+	protected ServerVariable strict() {
+		super.strict();
+		return this;
+	}
 
-    /**
-     * Bean property getter:  <property>enum</property>.
-     *
-     * <h5 class='section'>See Also:</h5>
-     * <ul>
-     * 	<li class='extlink'>{@doc JsonSchemaValidation}
-     * </ul>
-     *
-     * @return The property value, or <jk>null</jk> if it is not set.
-     */
-    public List<Object> getEnum() {
-        return _enum;
-    }
+	/**
+	 * Bean property getter:  <property>enum</property>.
+	 *
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='extlink'>{@doc JsonSchemaValidation}
+	 * </ul>
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public List<Object> getEnum() {
+		return _enum;
+	}
 
-    /**
-     * Bean property setter:  <property>enum</property>.
-     *
-     * <h5 class='section'>See Also:</h5>
-     * <ul>
-     * 	<li class='extlink'>{@doc JsonSchemaValidation}
-     * </ul>
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public ServerVariable setEnum(Collection<Object> value) {
-        _enum = newList(value);
-        return this;
-    }
+	/**
+	 * Bean property setter:  <property>enum</property>.
+	 *
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='extlink'>{@doc JsonSchemaValidation}
+	 * </ul>
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public ServerVariable setEnum(Collection<Object> value) {
+		_enum = listFrom(value);
+		return this;
+	}
 
-    /**
-     * Adds one or more values to the <property>enum</property> property.
-     *
-     * @param values
-     * 	The values to add to this property.
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public ServerVariable addEnum(Collection<Object> values) {
-        _enum = addToList(_enum, values);
-        return this;
-    }
+	/**
+	 * Adds one or more values to the <property>enum</property> property.
+	 *
+	 * @param values
+	 * 	The values to add to this property.
+	 * 	<br>Ignored if <jk>null</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public ServerVariable addEnum(Collection<Object> values) {
+		_enum = listBuilder(_enum).sparse().addAny(values).build();
+		return this;
+	}
 
-    /**
-     * Adds one or more values to the <property>enum</property> property.
-     *
-     * @param values
-     * 	The values to add to this property.
-     * 	<br>Valid types:
-     * 	<ul>
-     * 		<li><code>Object</code>
-     * 		<li><code>Collection&lt;Object&gt;</code>
-     * 		<li><code>String</code> - JSON array representation of <code>Collection&lt;Object&gt;</code>
-     * 			<h5 class='figure'>Example:</h5>
-     * 			<p class='bcode w800'>
-     * 	_enum(<js>"['foo','bar']"</js>);
-     * 			</p>
-     * 		<li><code>String</code> - Individual values
-     * 			<h5 class='figure'>Example:</h5>
-     * 			<p class='bcode w800'>
-     * 	_enum(<js>"foo"</js>, <js>"bar"</js>);
-     * 			</p>
-     * 	</ul>
-     * 	<br>Ignored if <jk>null</jk>.
-     * @return This object (for method chaining).
-     */
-    public ServerVariable _enum(Object...values) {
-        _enum = addToList(_enum, values, Object.class);
-        return this;
-    }
+	/**
+	 * Adds one or more values to the <property>enum</property> property.
+	 *
+	 * @param values
+	 * 	The values to add to this property.
+	 * 	<br>Valid types:
+	 * 	<ul>
+	 * 		<li><code>Object</code>
+	 * 		<li><code>Collection&lt;Object&gt;</code>
+	 * 		<li><code>String</code> - JSON array representation of <code>Collection&lt;Object&gt;</code>
+	 * 			<h5 class='figure'>Example:</h5>
+	 * 			<p class='bcode w800'>
+	 * 	_enum(<js>"['foo','bar']"</js>);
+	 * 			</p>
+	 * 		<li><code>String</code> - Individual values
+	 * 			<h5 class='figure'>Example:</h5>
+	 * 			<p class='bcode w800'>
+	 * 	_enum(<js>"foo"</js>, <js>"bar"</js>);
+	 * 			</p>
+	 * 	</ul>
+	 * 	<br>Ignored if <jk>null</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public ServerVariable _enum(Object...values) {
+		_enum = listBuilder(_enum).sparse().addAny(values).build();
+		return this;
+	}
 
-    /**
-     * Bean property getter:  <property>default</property>.
-     *
-     * <p>
-     * Declares the value of the item that the server will use if none is provided.
-     *
-     * <h5 class='section'>Notes:</h5>
-     * <ul class='spaced-list'>
-     * 	<li>
-     * 		<js>"default"</js> has no meaning for required items.
-     * 	<li>
-     * 		Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
-     * </ul>
-     *
-     * <h5 class='section'>See Also:</h5>
-     * <ul>
-     * 	<li class='extlink'>{@doc JsonSchemaValidation}
-     * </ul>
-     *
-     * @return The property value, or <jk>null</jk> if it is not set.
-     */
-    public String getDefault() {
-        return _default;
-    }
+	/**
+	 * Bean property getter:  <property>default</property>.
+	 *
+	 * <p>
+	 * Declares the value of the item that the server will use if none is provided.
+	 *
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul class='spaced-list'>
+	 * 	<li>
+	 * 		<js>"default"</js> has no meaning for required items.
+	 * 	<li>
+	 * 		Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
+	 * </ul>
+	 *
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='extlink'>{@doc JsonSchemaValidation}
+	 * </ul>
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public String getDefault() {
+		return _default;
+	}
 
-    /**
-     * Bean property setter:  <property>default</property>.
-     *
-     * <p>
-     * Declares the value of the item that the server will use if none is provided.
-     *
-     * <h5 class='section'>Notes:</h5>
-     * <ul class='spaced-list'>
-     * 	<li>
-     * 		<js>"default"</js> has no meaning for required items.
-     * 	<li>
-     * 		Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
-     * </ul>
-     *
-     * <h5 class='section'>See Also:</h5>
-     * <ul>
-     * 	<li class='extlink'>{@doc JsonSchemaValidation}
-     * </ul>
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public ServerVariable setDefault(String value) {
-        _default = value;
-        return this;
-    }
+	/**
+	 * Bean property setter:  <property>default</property>.
+	 *
+	 * <p>
+	 * Declares the value of the item that the server will use if none is provided.
+	 *
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul class='spaced-list'>
+	 * 	<li>
+	 * 		<js>"default"</js> has no meaning for required items.
+	 * 	<li>
+	 * 		Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
+	 * </ul>
+	 *
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='extlink'>{@doc JsonSchemaValidation}
+	 * </ul>
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public ServerVariable setDefault(String value) {
+		_default = value;
+		return this;
+	}
 
-    /**
-     * Same as {@link #setDefault(String)}.
-     *
-     * @param value
-     * 	The new value for this property.
-     * 	<br>Can be <jk>null</jk> to unset the property.
-     * @return This object (for method chaining).
-     */
-    public ServerVariable _default(Object value) {
-        return setDefault(toStringVal(value));
-    }
+	/**
+	 * Same as {@link #setDefault(String)}.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>Can be <jk>null</jk> to unset the property.
+	 * @return This object (for method chaining).
+	 */
+	public ServerVariable _default(Object value) {
+		return setDefault(stringify(value));
+	}
 
-    /**
-     * Returns <jk>true</jk> if the defualt property is not null or empty.
-     *
-     * @return <jk>true</jk> if the defualt property is not null or empty.
-     */
-    public boolean hasDefault() {
-        return ! _default.isEmpty();
-    }
+	/**
+	 * Returns <jk>true</jk> if the defualt property is not null or empty.
+	 *
+	 * @return <jk>true</jk> if the defualt property is not null or empty.
+	 */
+	public boolean hasDefault() {
+		return ! _default.isEmpty();
+	}
 
-    /**
-     * Bean property getter:  <property>description</property>.
-     *
-     * <p>
-     * Declares the value of the item that the server will use if none is provided.
-     *
-     * <h5 class='section'>Notes:</h5>
-     * <ul class='spaced-list'>
-     * 	<li>
-     * 		<js>"description"</js> has no meaning for required items.
-     * 	<li>
-     * 		Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
-     * </ul>
-     *
-     * <h5 class='section'>See Also:</h5>
-     * <ul>
-     * 	<li class='extlink'>{@doc JsonSchemaValidation}
-     * </ul>
-     *
-     */
-    public String getDescription() {
-        return description;
-    }
+	/**
+	 * Bean property getter:  <property>description</property>.
+	 *
+	 * <p>
+	 * Declares the value of the item that the server will use if none is provided.
+	 *
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul class='spaced-list'>
+	 * 	<li>
+	 * 		<js>"description"</js> has no meaning for required items.
+	 * 	<li>
+	 * 		Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
+	 * </ul>
+	 *
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='extlink'>{@doc JsonSchemaValidation}
+	 * </ul>
+	 *
+	 * @return The property value, or <jk>null</jk> if it is not set.
+	 */
+	public String getDescription() {
+		return description;
+	}
 
-    /**
-     * Bean property setter:  <property>description</property>.
-     *
-     * <p>
-     * Declares the value of the item that the server will use if none is provided.
-     *
-     * <h5 class='section'>Notes:</h5>
-     * <ul class='spaced-list'>
-     * 	<li>
-     * 		<js>"description"</js> has no meaning for required items.
-     * 	<li>
-     * 		Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
-     * </ul>
-     *
-     * <h5 class='section'>See Also:</h5>
-     * <ul>
-     * 	<li class='extlink'>{@doc JsonSchemaValidation}
-     * </ul>
-     *
-     * @param value
-     * 	The new value for this property.
-     * @return This object (for method chaining).
-     */
-    public ServerVariable setDescription(String value) {
-        description = value;
-        return this;
-    }
+	/**
+	 * Bean property setter:  <property>description</property>.
+	 *
+	 * <p>
+	 * Declares the value of the item that the server will use if none is provided.
+	 *
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul class='spaced-list'>
+	 * 	<li>
+	 * 		<js>"description"</js> has no meaning for required items.
+	 * 	<li>
+	 * 		Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
+	 * </ul>
+	 *
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='extlink'>{@doc JsonSchemaValidation}
+	 * </ul>
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * @return This object (for method chaining).
+	 */
+	public ServerVariable setDescription(String value) {
+		description = value;
+		return this;
+	}
 
-    /**
-     * Same as {@link #setDescription(String)}.
-     *
-     * @param value
-     * 	The new value for this property.
-     * @return This object (for method chaining).
-     */
-    public ServerVariable description(Object value) {
-        return setDefault(toStringVal(value));
-    }
+	/**
+	 * Same as {@link #setDescription(String)}.
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * @return This object (for method chaining).
+	 */
+	public ServerVariable description(Object value) {
+		return setDefault(stringify(value));
+	}
 
-    @Override /* OpenApiElement */
-    public <T> T get(String property, Class<T> type) {
-        if (property == null)
-            return null;
-        switch (property) {
-            case "enum": return toType(getEnum(), type);
-            case "default": return toType(getDefault(), type);
-            case "description": return toType(getDescription(), type);
-            default: return super.get(property, type);
-        }
-    }
+	@Override /* OpenApiElement */
+	public <T> T get(String property, Class<T> type) {
+		if (property == null)
+			return null;
+		switch (property) {
+			case "enum": return toType(getEnum(), type);
+			case "default": return toType(getDefault(), type);
+			case "description": return toType(getDescription(), type);
+			default: return super.get(property, type);
+		}
+	}
 
-    @Override /* OpenApiElement */
-    public ServerVariable set(String property, Object value) {
-        if (property == null)
-            return this;
-        switch (property) {
-            case "default": return _default(value);
-            case "enum": return setEnum(null)._enum(value);
-            case "description": return description(value);
-            default:
-                super.set(property, value);
-                return this;
-        }
-    }
+	@Override /* OpenApiElement */
+	public ServerVariable set(String property, Object value) {
+		if (property == null)
+			return this;
+		switch (property) {
+			case "default": return _default(value);
+			case "enum": return setEnum(null)._enum(value);
+			case "description": return description(value);
+			default:
+				super.set(property, value);
+				return this;
+		}
+	}
 
-    @Override /* OpenApiElement */
-    public Set<String> keySet() {
-        ASet<String> s = new ASet<String>()
-                .appendIf(_enum != null, "enum")
-                .appendIf(_default != null,"default" )
-                .appendIf(description != null, "description");
-        return new MultiSet<>(s, super.keySet());
+	@Override /* OpenApiElement */
+	public Set<String> keySet() {
+		Set<String> s = setBuilder(String.class)
+				.addIf(_enum != null, "enum")
+				.addIf(_default != null,"default" )
+				.addIf(description != null, "description")
+				.build();
+		return new MultiSet<>(s, super.keySet());
 
 
-    }
+	}
 }
\ No newline at end of file
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Tag.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Tag.java
index 5a0cd83fe..5e70b4582 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Tag.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Tag.java
@@ -12,17 +12,16 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
 import org.apache.juneau.annotation.Bean;
 import org.apache.juneau.dto.swagger.ExternalDocumentation;
-import org.apache.juneau.dto.swagger.SwaggerElement;
 import org.apache.juneau.internal.MultiSet;
-import org.apache.juneau.utils.ASet;
 
 import java.util.Set;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.toStringVal;
-import static org.apache.juneau.internal.BeanPropertyUtils.toType;
-
 /**
  * Allows adding meta data to a single tag that is used by the {@doc SwaggerOperationObject Operation Object}.
  *
@@ -128,7 +127,7 @@ public class Tag extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Tag name(Object value) {
-		return setName(toStringVal(value));
+		return setName(stringify(value));
 	}
 
 	/**
@@ -170,7 +169,7 @@ public class Tag extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Tag description(Object value) {
-		return setDescription(toStringVal(value));
+		return setDescription(stringify(value));
 	}
 
 	/**
@@ -250,10 +249,11 @@ public class Tag extends OpenApiElement {
 
 	@Override /* OpenApiElement */
 	public Set<String> keySet() {
-		ASet<String> s = new ASet<String>()
-			.appendIf(name != null, "name")
-			.appendIf(description != null, "description")
-			.appendIf(externalDocs != null, "externalDocs");
+		Set<String> s = setBuilder(String.class)
+			.addIf(name != null, "name")
+			.addIf(description != null, "description")
+			.addIf(externalDocs != null, "externalDocs")
+			.build();
 		return new MultiSet<>(s, super.keySet());
 	}
 }
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Xml.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Xml.java
index 2a569d327..3345ba389 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Xml.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/openapi/Xml.java
@@ -12,15 +12,15 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.dto.openapi;
 
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ConverterUtils.*;
+
 import org.apache.juneau.annotation.Bean;
-import org.apache.juneau.dto.swagger.SwaggerElement;
 import org.apache.juneau.internal.MultiSet;
-import org.apache.juneau.utils.ASet;
 
 import java.util.Set;
 
-import static org.apache.juneau.internal.BeanPropertyUtils.*;
-
 /**
  * A metadata object that allows for more fine-tuned XML model definitions.
  *
@@ -119,7 +119,7 @@ public class Xml extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Xml name(Object value) {
-		return setName(toStringVal(value));
+		return setName(stringify(value));
 	}
 
 	/**
@@ -160,7 +160,7 @@ public class Xml extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Xml namespace(Object value) {
-		return setNamespace(toStringVal(value));
+		return setNamespace(stringify(value));
 	}
 
 	/**
@@ -201,7 +201,7 @@ public class Xml extends OpenApiElement {
 	 * @return This object (for method chaining).
 	 */
 	public Xml prefix(Object value) {
-		return setPrefix(toStringVal(value));
+		return setPrefix(stringify(value));
 	}
 
 	/**
@@ -334,12 +334,13 @@ public class Xml extends OpenApiElement {
 
 	@Override /* OpenApiElement */
 	public Set<String> keySet() {
-		ASet<String> s = new ASet<String>()
-			.appendIf(name != null, "name")
-			.appendIf(namespace != null, "namespace")
-			.appendIf(prefix != null, "prefix")
-			.appendIf(attribute != null, "attribute")
-			.appendIf(wrapped != null, "wrapped");
+		Set<String> s = setBuilder(String.class)
+			.addIf(name != null, "name")
+			.addIf(namespace != null, "namespace")
+			.addIf(prefix != null, "prefix")
+			.addIf(attribute != null, "attribute")
+			.addIf(wrapped != null, "wrapped")
+			.build();
 		return new MultiSet<>(s, super.keySet());
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/CollectionUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/CollectionUtils.java
index 80e3d3b6c..6be8cb728 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/CollectionUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/CollectionUtils.java
@@ -47,6 +47,17 @@ public final class CollectionUtils {
 		return val == null ? null : new LinkedHashSet<>(val);
 	}
 
+	/**
+	 * Creates a new collection from the specified collection.
+	 *
+	 * @param <E> The element type.
+	 * @param val The value to copy from.
+	 * @return A new {@link LinkedHashSet}, or <jk>null</jk> if the input was null.
+	 */
+	public static <E> Collection<E> copyOf(Collection<E> val) {
+		return val == null ? null : new LinkedHashSet<>(val);
+	}
+
 	/**
 	 * Creates a new map from the specified map.
 	 *
diff --git a/juneau-doc/docs/Topics/16.juneau-petstore/01.jp.Installing.html b/juneau-doc/docs/Topics/16.juneau-petstore/01.jp.Installing.html
deleted file mode 100644
index c7daec4f4..000000000
--- a/juneau-doc/docs/Topics/16.juneau-petstore/01.jp.Installing.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-/***************************************************************************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *  
- *  http://www.apache.org/licenses/LICENSE-2.0
- *  
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations under the License.
- ***************************************************************************************************************************/
- -->
-
-{title:'Installing in Eclipse', created:'8.2.0', flags:'todo'} 
-
-<div class='topic'>
-	<p>
-		How to import Petstore to Eclipse or Spring Tool Suite: <br><br>
-		<ol>
-			<li>File --> </li>
-			<li>Import --> </li>
-			<li>Existing Maven Projects--></li>
-			<li>Browse existing projects--> juneau-petstore</li>
-		</ol>
-	</p>		
-</div>
\ No newline at end of file
diff --git a/juneau-doc/docs/Topics/16.juneau-petstore/02.jp.Running.html b/juneau-doc/docs/Topics/16.juneau-petstore/02.jp.Running.html
deleted file mode 100644
index d97084525..000000000
--- a/juneau-doc/docs/Topics/16.juneau-petstore/02.jp.Running.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!--
-/***************************************************************************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *  
- *  http://www.apache.org/licenses/LICENSE-2.0
- *  
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations under the License.
- ***************************************************************************************************************************/
- -->
-
-{title:'Running Petstore manually', created:'8.2.0', flags:'todo'} 
-
-<div class='topic'>
-	<p>
-			How to run Petstore --Java Backend-- in Eclipse or Spring Tool Suite: <br><br>
-		<ol>
-			<li>App.java --> Run as Spring Boot App </li>
-			<li>Main.java --> Run as Spring Boot App </li>
-		</ol>
-	</p>
-	<p>
-			How to run Petstore --React Frontend-- with npm: <br><br>
-		<ol>
-			<li>Install latest node.js </li>
-			<li>Inside folder "Pets" run command: npm install </li>
-			<li>Inside folder "Pets" run command: npm start  </li>
-		</ol>
-	</p>
-</div>
\ No newline at end of file
diff --git a/juneau-doc/docs/Topics/16.juneau-petstore/03.jp.Building.html b/juneau-doc/docs/Topics/16.juneau-petstore/03.jp.Building.html
deleted file mode 100644
index bb6857d54..000000000
--- a/juneau-doc/docs/Topics/16.juneau-petstore/03.jp.Building.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-/***************************************************************************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *  
- *  http://www.apache.org/licenses/LICENSE-2.0
- *  
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations under the License.
- ***************************************************************************************************************************/
- -->
-
-{title:'Building and Running from Command-Line (Using Dockerfiles)', created:'8.2.0', flags:'todo'} 
-
-<div class='topic'>
-	<p>
-			How to build and run Petstore using Docker: <br>
-		<ol>
-		<li>Go to the folder "juneau-petstore" and run this command: 
-				<br> 
-			docker build . -t petstore && docker run -p 5000:5000 petstore</li>
-		<br>
-		<li>Go to the folder "pets" and run this command:  
-				<br>
-			docker run --rm -it -p 3000:3000 -v $(pwd):/usr/src/app pets </li>
-		</ol>
-	</p>
-</div>
\ No newline at end of file
diff --git a/juneau-doc/docs/Topics/16.juneau-petstore/04.jp.App.html b/juneau-doc/docs/Topics/16.juneau-petstore/04.jp.App.html
deleted file mode 100644
index 454f634e2..000000000
--- a/juneau-doc/docs/Topics/16.juneau-petstore/04.jp.App.html
+++ /dev/null
@@ -1,80 +0,0 @@
-<!--
-/***************************************************************************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *  
- *  http://www.apache.org/licenses/LICENSE-2.0
- *  
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations under the License.
- ***************************************************************************************************************************/
- -->
-
-{title:'About Petstore App', created:'8.2.0', flags:'todo'} 
-
-
-<div class='topic'>
-	<div style="width: 70%;">
-	    <h3 style="color: blue;">
-	        What is the Petstore app?
-	    </h3>
-	    <p>
-	
-	        Petstore is a simple CRUD (Create, Read, Update and Delete) application,
-	        which is meant to demonstrate the advantages of the Apache Juneau library.
-	        It is a live example showing how any JAVA back-end developer can use Juneau for parsing,
-	        POJO serialization and sending different types of serialized POJOs over REST.
-	
-	    </p>
-	    <h3>What's the project layout?</h3>
-	    <p> Petstore application consists of three main parts, which are connected over REST:
-	        <ul>
-	            <li>Database: Apache Derby.</li>
-	            <li>Server: Java Spring Boot. </li>
-	            <li>Client: Java Spring Boot or React.</li>
-	        </ul>
-	    </p>
-	
-	    <p> Java back-end and front-end runs on: http://localhost:5000;
-	        <br>React front-end runs on: http://localhost:3000.
-	    </p>
-	
-	    <p> Project is based on a standard Spring Boot project structure. There are Models, Repositories, Services.
-	        <br>The main difference here - no Controller classes or @RestController annotations.
-	        Instead of it, we use PetStore.java interface class where REST calls are mapped with different methods.
-	    </p>
-	    <p>Petstore has three types of DTO objects (database entities): Pets, Orders and Users. </p>
-	    <p>All methods for creating, reading, updating or deleting database entities (pets, orders or users) are provided in
-	        PetStoreService.java class. </p>
-	    <p> Example Pet, Order and User objects are created at program
-	        startup and saved in the database using JPA (Java Persistence API) and PetStoreService methods.</p>
-	
-	    <h3>How does it work ?</h3>
-	    <p>
-	        <ul>
-	
-	            <li>To get the data which should be displayed, Petstore app client
-	                sends http request GET to the back-end server. The response data goes
-	                over the REST connection where POJOs get serialized.
-	                Petstore client can get and display different types of the same POJO:
-	                simple (standard) json format and other (not standard) formats.
-	
-	            <li>Response data (array of objects) in standard JSON format here is used to generate table content
-	                (for example, all Pets in Store).</li>
-	
-	            <li>Other types of these objects are displayed in the page section "Content types".
-	                Here you can get the same POJOs displayed in different formats: json simple, json schema,
-	                www form urlencoded, octal/msg, html, html schema, html stripped, openapi, plain text, uon, xml, xml
-	                schema, xml soap.
-	            </li>
-	            <li>All readable table content and visual representation of the different content types are generated from
-	                the response data.</li>
-	        </ul>
-	
-	    </p>
-	
-	</div>
-</div>
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/App.java b/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/App.java
index ff9fe9e4a..d0f205243 100644
--- a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/App.java
+++ b/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/App.java
@@ -34,6 +34,10 @@ import org.springframework.stereotype.Controller;
 @Controller
 public class App {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Entry point
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Entry point method.
 	 * @param args Command-line arguments.
@@ -48,6 +52,10 @@ public class App {
 		}
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Beans
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Our root REST bean.
 	 * <p>