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 10bf335329 FilteredMap/MapBuilder improvements
10bf335329 is described below

commit 10bf3353294f84a7f1e4fbdd6ad7ac9633501090
Author: James Bognar <[email protected]>
AuthorDate: Sun Dec 14 16:29:18 2025 -0500

    FilteredMap/MapBuilder improvements
---
 .../apache/juneau/bean/openapi3/Discriminator.java |  12 +--
 .../org/apache/juneau/bean/openapi3/Encoding.java  |  15 ++--
 .../apache/juneau/bean/openapi3/HeaderInfo.java    |  15 ++--
 .../java/org/apache/juneau/bean/openapi3/Link.java |  15 ++--
 .../org/apache/juneau/bean/openapi3/MediaType.java |  30 ++++---
 .../org/apache/juneau/bean/openapi3/OAuthFlow.java |  15 ++--
 .../org/apache/juneau/bean/openapi3/Operation.java |  32 ++++---
 .../juneau/bean/openapi3/RequestBodyInfo.java      |  15 ++--
 .../org/apache/juneau/bean/openapi3/Response.java  |  51 ++++++-----
 .../org/apache/juneau/bean/openapi3/Server.java    |  15 ++--
 .../org/apache/juneau/bean/swagger/Operation.java  |  22 +++--
 .../apache/juneau/bean/swagger/ResponseInfo.java   |  35 ++++----
 .../org/apache/juneau/bean/swagger/SchemaInfo.java |  18 ++--
 .../apache/juneau/bean/swagger/SecurityScheme.java |  15 ++--
 .../org/apache/juneau/bean/swagger/Swagger.java    |  89 ++++++++++--------
 .../juneau/commons/collections/FilteredList.java   |   1 -
 .../juneau/commons/collections/FilteredSet.java    |   1 -
 .../juneau/commons/collections/MapBuilder.java     |  14 ---
 .../commons/function/ResettableSupplier.java       |  29 ++++++
 .../org/apache/juneau/commons/io/LocalDir.java     |   4 +-
 .../apache/juneau/commons/utils/StringUtils.java   |  10 ---
 .../org/apache/juneau/commons/utils/Utils.java     | 100 ++++++++++++++++++++-
 .../main/java/org/apache/juneau/config/Config.java |   3 +-
 .../main/java/org/apache/juneau/UriContext.java    |  18 ++--
 .../java/org/apache/juneau/cp/BeanStoreEntry.java  |   4 +-
 .../rest/client/remote/RemoteOperationMeta.java    |   2 +-
 .../java/org/apache/juneau/rest/RestContext.java   |   4 +-
 .../org/apache/juneau/rest/util/UrlPathMatch.java  |   3 +-
 .../apache/juneau/rest/widget/MenuItemWidget.java  |   1 -
 .../juneau/bean/openapi3/Operation_Test.java       |   2 +-
 .../commons/collections/FilteredList_Test.java     |   1 -
 .../commons/collections/MapBuilder_Test.java       |  29 ------
 .../juneau/commons/utils/StringUtils_Test.java     |  29 ++----
 .../apache/juneau/commons/utils/Utils_Test.java    |  71 +++++++++++++++
 34 files changed, 453 insertions(+), 267 deletions(-)

diff --git 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Discriminator.java
 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Discriminator.java
index 224afaf1cb..207c4bfe74 100644
--- 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Discriminator.java
+++ 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Discriminator.java
@@ -75,7 +75,7 @@ import org.apache.juneau.commons.collections.*;
 public class Discriminator extends OpenApiElement {
 
        private String propertyName;
-       private Map<String,String> mapping;
+       private Map<String,String> mapping = map();
 
        /**
         * Default constructor.
@@ -104,7 +104,7 @@ public class Discriminator extends OpenApiElement {
        public Discriminator addMapping(String key, String value) {
                assertArgNotNull("key", key);
                assertArgNotNull("value", value);
-               mapping = mapb(String.class, 
String.class).to(mapping).sparse().add(key, value).build();
+               mapping.put(key, value);
                return this;
        }
 
@@ -135,7 +135,7 @@ public class Discriminator extends OpenApiElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,String> getMapping() { return mapping; }
+       public Map<String,String> getMapping() { return nullIfEmpty(mapping); }
 
        /**
         * Bean property getter:  <property>propertyName</property>.
@@ -151,7 +151,7 @@ public class Discriminator extends OpenApiElement {
        public Set<String> keySet() {
                // @formatter:off
                var s = setb(String.class)
-                       .addIf(nn(mapping), "mapping")
+                       .addIf(isNotEmpty(mapping), "mapping")
                        .addIf(nn(propertyName), "propertyName")
                        .build();
                // @formatter:on
@@ -185,7 +185,9 @@ public class Discriminator extends OpenApiElement {
         * @return This object
         */
        public Discriminator setMapping(Map<String,String> value) {
-               mapping = copyOf(value);
+               mapping.clear();
+               if (nn(value))
+                       mapping.putAll(value);
                return this;
        }
 
diff --git 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Encoding.java
 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Encoding.java
index 171d8ccb94..b7bfb89021 100644
--- 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Encoding.java
+++ 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Encoding.java
@@ -77,7 +77,7 @@ import org.apache.juneau.commons.collections.*;
 public class Encoding extends OpenApiElement {
 
        private String contentType, style;
-       private Map<String,HeaderInfo> headers;
+       private Map<String,HeaderInfo> headers = map();
        private Boolean explode, allowReserved;
 
        /**
@@ -97,7 +97,8 @@ public class Encoding extends OpenApiElement {
                this.style = copyFrom.style;
                this.explode = copyFrom.explode;
                this.allowReserved = copyFrom.allowReserved;
-               this.headers = copyOf(copyFrom.headers, HeaderInfo::copy);
+               if (nn(copyFrom.headers))
+                       headers.putAll(copyOf(copyFrom.headers, 
HeaderInfo::copy));
        }
 
        /**
@@ -112,7 +113,7 @@ public class Encoding extends OpenApiElement {
        public Encoding addHeader(String key, HeaderInfo value) {
                assertArgNotNull("key", key);
                assertArgNotNull("value", value);
-               headers = mapb(String.class, 
HeaderInfo.class).to(headers).sparse().add(key, value).build();
+               headers.put(key, value);
                return this;
        }
 
@@ -173,7 +174,7 @@ public class Encoding extends OpenApiElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,HeaderInfo> getHeaders() { return headers; }
+       public Map<String,HeaderInfo> getHeaders() { return 
nullIfEmpty(headers); }
 
        /**
         * Bean property getter:  <property>style</property>.
@@ -189,7 +190,7 @@ public class Encoding extends OpenApiElement {
                        .addIf(nn(allowReserved), "allowReserved")
                        .addIf(nn(contentType), "contentType")
                        .addIf(nn(explode), "explode")
-                       .addIf(nn(headers), "headers")
+                       .addIf(isNotEmpty(headers), "headers")
                        .addIf(nn(style), "style")
                        .build();
                // @formatter:on
@@ -275,7 +276,9 @@ public class Encoding extends OpenApiElement {
         * @return This object
         */
        public Encoding setHeaders(Map<String,HeaderInfo> value) {
-               headers = copyOf(value);
+               headers.clear();
+               if (nn(value))
+                       headers.putAll(value);
                return this;
        }
 
diff --git 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/HeaderInfo.java
 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/HeaderInfo.java
index 918065977f..fdb3acebaa 100644
--- 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/HeaderInfo.java
+++ 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/HeaderInfo.java
@@ -81,7 +81,7 @@ public class HeaderInfo extends OpenApiElement {
        private Boolean required, explode, deprecated, allowEmptyValue, 
allowReserved;
        private SchemaInfo schema;
        private Object example;
-       private Map<String,Example> examples;
+       private Map<String,Example> examples = map();
 
        /**
         * Default constructor.
@@ -105,7 +105,8 @@ public class HeaderInfo extends OpenApiElement {
                this.ref = copyFrom.ref;
                this.explode = copyFrom.explode;
                this.deprecated = copyFrom.deprecated;
-               this.examples = copyOf(copyFrom.examples, Example::copy);
+               if (nn(copyFrom.examples))
+                       examples.putAll(copyOf(copyFrom.examples, 
Example::copy));
        }
 
        /**
@@ -118,7 +119,7 @@ public class HeaderInfo extends OpenApiElement {
        public HeaderInfo addExample(String name, Example example) {
                assertArgNotNull("name", name);
                assertArgNotNull("example", example);
-               examples = mapb(String.class, 
Example.class).to(examples).sparse().add(name, example).build();
+               examples.put(name, example);
                return this;
        }
 
@@ -205,7 +206,7 @@ public class HeaderInfo extends OpenApiElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,Example> getExamples() { return examples; }
+       public Map<String,Example> getExamples() { return 
nullIfEmpty(examples); }
 
        /**
         * Bean property getter:  <property>required</property>.
@@ -251,7 +252,7 @@ public class HeaderInfo extends OpenApiElement {
                        .addIf(nn(allowReserved), "allowReserved")
                        .addIf(nn(deprecated), "deprecated")
                        .addIf(nn(description), "description")
-                       .addIf(nn(examples), "examples")
+                       .addIf(isNotEmpty(examples), "examples")
                        .addIf(nn(explode), "explode")
                        .addIf(nn(required), "required")
                        .addIf(nn(schema), "schema")
@@ -399,7 +400,9 @@ public class HeaderInfo extends OpenApiElement {
         * @return This object
         */
        public HeaderInfo setExamples(Map<String,Example> value) {
-               examples = copyOf(value);
+               examples.clear();
+               if (nn(value))
+                       examples.putAll(value);
                return this;
        }
 
diff --git 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Link.java
 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Link.java
index 7bd014bb07..4e378a7cc0 100644
--- 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Link.java
+++ 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Link.java
@@ -69,7 +69,7 @@ public class Link extends OpenApiElement {
        private String description;
        private Object requestBody;
        private Server server;
-       private Map<String,Object> parameters;
+       private Map<String,Object> parameters = map();
 
        /**
         * Default constructor.
@@ -89,7 +89,8 @@ public class Link extends OpenApiElement {
                this.operationId = copyFrom.operationId;
                this.requestBody = copyFrom.requestBody;
                this.server = copyFrom.server == null ? null : 
copyFrom.server.copy();
-               this.parameters = copyOf(copyFrom.parameters);
+               if (nn(copyFrom.parameters))
+                       parameters.putAll(copyFrom.parameters);
        }
 
        /**
@@ -102,7 +103,7 @@ public class Link extends OpenApiElement {
        public Link addParameter(String mimeType, Object parameter) {
                assertArgNotNull("mimeType", mimeType);
                assertArgNotNull("parameter", parameter);
-               parameters = mapb(String.class, 
Object.class).to(parameters).sparse().add(mimeType, parameter).build();
+               parameters.put(mimeType, parameter);
                return this;
        }
 
@@ -167,7 +168,7 @@ public class Link extends OpenApiElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,Object> getParameters() { return parameters; }
+       public Map<String,Object> getParameters() { return 
nullIfEmpty(parameters); }
 
        /**
         * Bean property getter:  <property>default</property>.
@@ -197,7 +198,7 @@ public class Link extends OpenApiElement {
                        .addIf(nn(description), "description")
                        .addIf(nn(operationId), "operationId")
                        .addIf(nn(operationRef), "operationRef")
-                       .addIf(nn(parameters), "parameters")
+                       .addIf(isNotEmpty(parameters), "parameters")
                        .addIf(nn(requestBody), "requestBody")
                        .addIf(nn(server), "server")
                        .build();
@@ -280,7 +281,9 @@ public class Link extends OpenApiElement {
         * @return This object
         */
        public Link setParameters(Map<String,Object> value) {
-               parameters = copyOf(value);
+               parameters.clear();
+               if (nn(value))
+                       parameters.putAll(value);
                return this;
        }
 
diff --git 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/MediaType.java
 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/MediaType.java
index f470bfbc27..603524e5a7 100644
--- 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/MediaType.java
+++ 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/MediaType.java
@@ -71,8 +71,8 @@ import org.apache.juneau.commons.collections.*;
 public class MediaType extends OpenApiElement {
        private SchemaInfo schema;
        private Object example;
-       private Map<String,Example> examples;
-       private Map<String,Encoding> encoding;
+       private Map<String,Example> examples = map();
+       private Map<String,Encoding> encoding = map();
 
        /**
         * Default constructor.
@@ -89,8 +89,10 @@ public class MediaType extends OpenApiElement {
 
                this.schema = copyFrom.schema;
                this.example = copyFrom.example;
-               this.examples = copyOf(copyFrom.examples, Example::copy);
-               this.encoding = copyOf(copyFrom.encoding, Encoding::copy);
+               if (nn(copyFrom.examples))
+                       examples.putAll(copyOf(copyFrom.examples, 
Example::copy));
+               if (nn(copyFrom.encoding))
+                       encoding.putAll(copyOf(copyFrom.encoding, 
Encoding::copy));
        }
 
        /**
@@ -105,7 +107,7 @@ public class MediaType extends OpenApiElement {
        public MediaType addEncoding(String key, Encoding value) {
                assertArgNotNull("key", key);
                assertArgNotNull("value", value);
-               encoding = mapb(String.class, 
Encoding.class).to(encoding).sparse().add(key, value).build();
+               encoding.put(key, value);
                return this;
        }
 
@@ -119,7 +121,7 @@ public class MediaType extends OpenApiElement {
        public MediaType addExample(String name, Example example) {
                assertArgNotNull("name", name);
                assertArgNotNull("example", example);
-               examples = mapb(String.class, 
Example.class).to(examples).add(name, example).build();
+               examples.put(name, example);
                return this;
        }
 
@@ -149,7 +151,7 @@ public class MediaType extends OpenApiElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,Encoding> getEncoding() { return encoding; }
+       public Map<String,Encoding> getEncoding() { return 
nullIfEmpty(encoding); }
 
        /**
         * Bean property getter:  <property>x-example</property>.
@@ -167,7 +169,7 @@ public class MediaType extends OpenApiElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,Example> getExamples() { return examples; }
+       public Map<String,Example> getExamples() { return 
nullIfEmpty(examples); }
 
        /**
         * Bean property getter:  <property>schema</property>.
@@ -182,8 +184,8 @@ public class MediaType extends OpenApiElement {
                var s = setb(String.class)
                        .addIf(nn(schema), "schema")
                        .addIf(nn(example), "x-example")
-                       .addIf(nn(encoding), "encoding")
-                       .addIf(nn(examples), "examples")
+                       .addIf(isNotEmpty(encoding), "encoding")
+                       .addIf(isNotEmpty(examples), "examples")
                        .build();
                // @formatter:on
                return new MultiSet<>(s, super.keySet());
@@ -213,7 +215,9 @@ public class MediaType extends OpenApiElement {
         * @return This object
         */
        public MediaType setEncoding(Map<String,Encoding> value) {
-               encoding = copyOf(value);
+               encoding.clear();
+               if (nn(value))
+                       encoding.putAll(value);
                return this;
        }
 
@@ -243,7 +247,9 @@ public class MediaType extends OpenApiElement {
         * @return This object
         */
        public MediaType setExamples(Map<String,Example> value) {
-               examples = copyOf(value);
+               examples.clear();
+               if (nn(value))
+                       examples.putAll(value);
                return this;
        }
 
diff --git 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OAuthFlow.java
 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OAuthFlow.java
index 3268ca6e9c..6305350810 100644
--- 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OAuthFlow.java
+++ 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OAuthFlow.java
@@ -80,7 +80,7 @@ public class OAuthFlow extends OpenApiElement {
        private String authorizationUrl;
        private String tokenUrl;
        private String refreshUrl;
-       private Map<String,String> scopes;
+       private Map<String,String> scopes = map();
 
        /**
         * Default constructor.
@@ -98,7 +98,8 @@ public class OAuthFlow extends OpenApiElement {
                this.authorizationUrl = copyFrom.authorizationUrl;
                this.tokenUrl = copyFrom.tokenUrl;
                this.refreshUrl = copyFrom.refreshUrl;
-               this.scopes = copyOf(copyFrom.scopes);
+               if (nn(copyFrom.scopes))
+                       scopes.putAll(copyFrom.scopes);
        }
 
        /**
@@ -111,7 +112,7 @@ public class OAuthFlow extends OpenApiElement {
        public OAuthFlow addScope(String name, String description) {
                assertArgNotNull("name", name);
                assertArgNotNull("description", description);
-               scopes = mapb(String.class, 
String.class).to(scopes).sparse().add(name, description).build();
+               scopes.put(name, description);
                return this;
        }
 
@@ -164,7 +165,7 @@ public class OAuthFlow extends OpenApiElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,String> getScopes() { return scopes; }
+       public Map<String,String> getScopes() { return nullIfEmpty(scopes); }
 
        /**
         * Bean property getter:  <property>description</property>.
@@ -182,7 +183,7 @@ public class OAuthFlow extends OpenApiElement {
                var s = setb(String.class)
                        .addIf(nn(authorizationUrl), "authorizationUrl")
                        .addIf(nn(refreshUrl), "refreshUrl")
-                       .addIf(nn(scopes), "scopes")
+                       .addIf(isNotEmpty(scopes), "scopes")
                        .addIf(nn(tokenUrl), "tokenUrl")
                        .build();
                // @formatter:on
@@ -250,7 +251,9 @@ public class OAuthFlow extends OpenApiElement {
         * @return This object
         */
        public OAuthFlow setScopes(Map<String,String> value) {
-               scopes = copyOf(value);
+               scopes.clear();
+               if (nn(value))
+                       scopes.putAll(value);
                return this;
        }
 
diff --git 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Operation.java
 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Operation.java
index 36b98fd468..cb08f30ece 100644
--- 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Operation.java
+++ 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Operation.java
@@ -96,8 +96,8 @@ public class Operation extends OpenApiElement {
        private ExternalDocumentation externalDocs;
        private List<Parameter> parameters;
        private RequestBodyInfo requestBody;
-       private Map<String,Response> responses;
-       private Map<String,Callback> callbacks;
+       private Map<String,Response> responses = map();
+       private Map<String,Callback> callbacks = map();
        private Boolean deprecated;
        private List<SecurityRequirement> security;
        private List<Server> servers;
@@ -121,8 +121,10 @@ public class Operation extends OpenApiElement {
                this.externalDocs = copyFrom.externalDocs;
                this.parameters = copyOf(copyFrom.parameters);
                this.requestBody = copyFrom.requestBody;
-               this.responses = copyOf(copyFrom.responses);
-               this.callbacks = copyOf(copyFrom.callbacks);
+               if (nn(copyFrom.responses))
+                       responses.putAll(copyFrom.responses);
+               if (nn(copyFrom.callbacks))
+                       callbacks.putAll(copyFrom.callbacks);
                this.deprecated = copyFrom.deprecated;
                this.security = copyOf(copyFrom.security);
                this.servers = copyOf(copyFrom.servers);
@@ -145,7 +147,7 @@ public class Operation extends OpenApiElement {
        public Operation addCallback(String name, Callback callback) {
                assertArgNotNull("name", name);
                assertArgNotNull("callback", callback);
-               callbacks = mapb(String.class, 
Callback.class).to(callbacks).sparse().add(name, callback).build();
+               callbacks.put(name, callback);
                return this;
        }
 
@@ -198,7 +200,7 @@ public class Operation extends OpenApiElement {
        public Operation addResponse(String statusCode, Response response) {
                assertArgNotNull("statusCode", statusCode);
                assertArgNotNull("response", response);
-               responses = mapb(String.class, 
Response.class).to(responses).sparse().add(statusCode, response).build();
+               responses.put(statusCode, response);
                return this;
        }
 
@@ -332,7 +334,7 @@ public class Operation extends OpenApiElement {
         *
         * @return The callbacks map.
         */
-       public Map<String,Callback> getCallbacks() { return callbacks; }
+       public Map<String,Callback> getCallbacks() { return 
nullIfEmpty(callbacks); }
 
        /**
         * Returns the deprecated flag.
@@ -411,7 +413,7 @@ public class Operation extends OpenApiElement {
         */
        public Response getResponse(String status) {
                assertArgNotNull("status", status);
-               return responses == null ? null : responses.get(status);
+               return responses.get(status);
        }
 
        /**
@@ -419,7 +421,7 @@ public class Operation extends OpenApiElement {
         *
         * @return The responses map.
         */
-       public Map<String,Response> getResponses() { return responses; }
+       public Map<String,Response> getResponses() { return 
nullIfEmpty(responses); }
 
        /**
         * Returns the security requirements list.
@@ -453,14 +455,14 @@ public class Operation extends OpenApiElement {
        public Set<String> keySet() {
                // @formatter:off
                var s = setb(String.class)
-                       .addIf(nn(callbacks), "callbacks")
+                       .addIf(isNotEmpty(callbacks), "callbacks")
                        .addIf(nn(deprecated), "deprecated")
                        .addIf(nn(description), "description")
                        .addIf(nn(externalDocs), "externalDocs")
                        .addIf(nn(operationId), "operationId")
                        .addIf(nn(parameters), "parameters")
                        .addIf(nn(requestBody), "requestBody")
-                       .addIf(nn(responses), "responses")
+                       .addIf(isNotEmpty(responses), "responses")
                        .addIf(nn(security), "security")
                        .addIf(nn(servers), "servers")
                        .addIf(nn(summary), "summary")
@@ -500,7 +502,9 @@ public class Operation extends OpenApiElement {
         * @return This object.
         */
        public Operation setCallbacks(Map<String,Callback> value) {
-               this.callbacks = value;
+               callbacks.clear();
+               if (nn(value))
+                       callbacks.putAll(value);
                return this;
        }
 
@@ -588,7 +592,9 @@ public class Operation extends OpenApiElement {
         * @return This object.
         */
        public Operation setResponses(Map<String,Response> value) {
-               this.responses = value;
+               responses.clear();
+               if (nn(value))
+                       responses.putAll(value);
                return this;
        }
 
diff --git 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/RequestBodyInfo.java
 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/RequestBodyInfo.java
index 0c3dba98a8..e865a86461 100644
--- 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/RequestBodyInfo.java
+++ 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/RequestBodyInfo.java
@@ -68,7 +68,7 @@ import org.apache.juneau.commons.collections.*;
 public class RequestBodyInfo extends OpenApiElement {
 
        private String description;
-       private Map<String,MediaType> content;
+       private Map<String,MediaType> content = map();
        private Boolean required;
 
        /**
@@ -86,7 +86,8 @@ public class RequestBodyInfo extends OpenApiElement {
 
                this.description = copyFrom.description;
                this.required = copyFrom.required;
-               this.content = copyOf(copyFrom.content, MediaType::copy);
+               if (nn(copyFrom.content))
+                       content.putAll(copyOf(copyFrom.content, 
MediaType::copy));
        }
 
        /**
@@ -102,7 +103,7 @@ public class RequestBodyInfo extends OpenApiElement {
        public RequestBodyInfo addContent(String key, MediaType value) {
                assertArgNotNull("key", key);
                assertArgNotNull("value", value);
-               content = mapb(String.class, 
MediaType.class).to(content).sparse().add(key, value).build();
+               content.put(key, value);
                return this;
        }
 
@@ -131,7 +132,7 @@ public class RequestBodyInfo extends OpenApiElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,MediaType> getContent() { return content; }
+       public Map<String,MediaType> getContent() { return 
nullIfEmpty(content); }
 
        /**
         * Bean property getter:  <property>contentType</property>.
@@ -157,7 +158,7 @@ public class RequestBodyInfo extends OpenApiElement {
        public Set<String> keySet() {
                // @formatter:off
                var s = setb(String.class)
-                       .addIf(nn(content), "content")
+                       .addIf(isNotEmpty(content), "content")
                        .addIf(nn(description), "description")
                        .addIf(nn(required), "required")
                        .build();
@@ -188,7 +189,9 @@ public class RequestBodyInfo extends OpenApiElement {
         * @return This object
         */
        public RequestBodyInfo setContent(Map<String,MediaType> value) {
-               content = copyOf(value);
+               content.clear();
+               if (nn(value))
+                       content.putAll(value);
                return this;
        }
 
diff --git 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Response.java
 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Response.java
index dbaba20550..01d5af6919 100644
--- 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Response.java
+++ 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Response.java
@@ -78,9 +78,9 @@ import org.apache.juneau.commons.collections.*;
 public class Response extends OpenApiElement {
 
        private String description;
-       private Map<String,HeaderInfo> headers;
-       private Map<String,MediaType> content;
-       private Map<String,Link> links;
+       private Map<String,HeaderInfo> headers = map();
+       private Map<String,MediaType> content = map();
+       private Map<String,Link> links = map();
 
        /**
         * Default constructor.
@@ -96,9 +96,12 @@ public class Response extends OpenApiElement {
                super(copyFrom);
 
                this.description = copyFrom.description;
-               this.headers = copyOf(copyFrom.headers, HeaderInfo::copy);
-               this.content = copyOf(copyFrom.content, MediaType::copy);
-               this.links = copyOf(copyFrom.links, Link::copy);
+               if (nn(copyFrom.headers))
+                       headers.putAll(copyOf(copyFrom.headers, 
HeaderInfo::copy));
+               if (nn(copyFrom.content))
+                       content.putAll(copyOf(copyFrom.content, 
MediaType::copy));
+               if (nn(copyFrom.links))
+                       links.putAll(copyOf(copyFrom.links, Link::copy));
        }
 
        /**
@@ -111,7 +114,7 @@ public class Response extends OpenApiElement {
        public Response addContent(String key, MediaType value) {
                assertArgNotNull("key", key);
                assertArgNotNull("value", value);
-               content = mapb(String.class, 
MediaType.class).to(content).sparse().add(key, value).build();
+               content.put(key, value);
                return this;
        }
 
@@ -125,7 +128,7 @@ public class Response extends OpenApiElement {
        public Response addHeader(String key, HeaderInfo value) {
                assertArgNotNull("key", key);
                assertArgNotNull("value", value);
-               headers = mapb(String.class, 
HeaderInfo.class).to(headers).sparse().add(key, value).build();
+               headers.put(key, value);
                return this;
        }
 
@@ -139,7 +142,7 @@ public class Response extends OpenApiElement {
        public Response addLink(String key, Link value) {
                assertArgNotNull("key", key);
                assertArgNotNull("value", value);
-               links = mapb(String.class, 
Link.class).to(links).sparse().add(key, value).build();
+               links.put(key, value);
                return this;
        }
 
@@ -169,7 +172,7 @@ public class Response extends OpenApiElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,MediaType> getContent() { return content; }
+       public Map<String,MediaType> getContent() { return 
nullIfEmpty(content); }
 
        /**
         * Returns the content with the specified media type.
@@ -179,7 +182,7 @@ public class Response extends OpenApiElement {
         */
        public MediaType getContent(String mediaType) {
                assertArgNotNull("mediaType", mediaType);
-               return content == null ? null : content.get(mediaType);
+               return content.get(mediaType);
        }
 
        /**
@@ -200,7 +203,7 @@ public class Response extends OpenApiElement {
         */
        public HeaderInfo getHeader(String name) {
                assertArgNotNull("name", name);
-               return headers == null ? null : headers.get(name);
+               return headers.get(name);
        }
 
        /**
@@ -208,7 +211,7 @@ public class Response extends OpenApiElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,HeaderInfo> getHeaders() { return headers; }
+       public Map<String,HeaderInfo> getHeaders() { return 
nullIfEmpty(headers); }
 
        /**
         * Returns the link with the specified name.
@@ -218,7 +221,7 @@ public class Response extends OpenApiElement {
         */
        public Link getLink(String name) {
                assertArgNotNull("name", name);
-               return links == null ? null : links.get(name);
+               return links.get(name);
        }
 
        /**
@@ -226,16 +229,16 @@ public class Response extends OpenApiElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,Link> getLinks() { return links; }
+       public Map<String,Link> getLinks() { return nullIfEmpty(links); }
 
        @Override /* Overridden from OpenApiElement */
        public Set<String> keySet() {
                // @formatter:off
                var s = setb(String.class)
-                       .addIf(nn(content), "content")
+                       .addIf(isNotEmpty(content), "content")
                        .addIf(nn(description), "description")
-                       .addIf(nn(headers), "headers")
-                       .addIf(nn(links), "links")
+                       .addIf(isNotEmpty(headers), "headers")
+                       .addIf(isNotEmpty(links), "links")
                        .build();
                // @formatter:on
                return new MultiSet<>(s, super.keySet());
@@ -265,7 +268,9 @@ public class Response extends OpenApiElement {
         * @return This object
         */
        public Response setContent(Map<String,MediaType> value) {
-               content = copyOf(value);
+               content.clear();
+               if (nn(value))
+                       content.putAll(value);
                return this;
        }
 
@@ -298,7 +303,9 @@ public class Response extends OpenApiElement {
         * @return This object
         */
        public Response setHeaders(Map<String,HeaderInfo> value) {
-               headers = copyOf(value);
+               headers.clear();
+               if (nn(value))
+                       headers.putAll(value);
                return this;
        }
 
@@ -311,7 +318,9 @@ public class Response extends OpenApiElement {
         * @return This object
         */
        public Response setLinks(Map<String,Link> value) {
-               links = copyOf(value);
+               links.clear();
+               if (nn(value))
+                       links.putAll(value);
                return this;
        }
 
diff --git 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Server.java
 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Server.java
index c6cc3dad36..dbf22d8d28 100644
--- 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Server.java
+++ 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Server.java
@@ -74,7 +74,7 @@ import org.apache.juneau.commons.collections.*;
 public class Server extends OpenApiElement {
        private URI url;
        private String description;
-       private Map<String,ServerVariable> variables;
+       private Map<String,ServerVariable> variables = map();
 
        /**
         * Default constructor.
@@ -91,7 +91,8 @@ public class Server extends OpenApiElement {
 
                this.url = copyFrom.url;
                this.description = copyFrom.description;
-               this.variables = copyOf(copyFrom.variables, 
ServerVariable::copy);
+               if (nn(copyFrom.variables))
+                       variables.putAll(copyOf(copyFrom.variables, 
ServerVariable::copy));
        }
 
        /**
@@ -107,7 +108,7 @@ public class Server extends OpenApiElement {
        public Server addVariable(String key, ServerVariable value) {
                assertArgNotNull("key", key);
                assertArgNotNull("value", value);
-               variables = mapb(String.class, 
ServerVariable.class).to(variables).sparse().add(key, value).build();
+               variables.put(key, value);
                return this;
        }
 
@@ -153,7 +154,7 @@ public class Server extends OpenApiElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,ServerVariable> getVariables() { return variables; }
+       public Map<String,ServerVariable> getVariables() { return 
nullIfEmpty(variables); }
 
        @Override /* Overridden from OpenApiElement */
        public Set<String> keySet() {
@@ -161,7 +162,7 @@ public class Server extends OpenApiElement {
                var s = setb(String.class)
                        .addIf(nn(description), "description")
                        .addIf(nn(url), "url")
-                       .addIf(nn(variables), "variables")
+                       .addIf(isNotEmpty(variables), "variables")
                        .build();
                // @formatter:on
                return new MultiSet<>(s, super.keySet());
@@ -223,7 +224,9 @@ public class Server extends OpenApiElement {
         * @return This object
         */
        public Server setVariables(Map<String,ServerVariable> value) {
-               variables = copyOf(value);
+               variables.clear();
+               if (nn(value))
+                       variables.putAll(value);
                return this;
        }
 
diff --git 
a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Operation.java
 
b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Operation.java
index 094f8833a5..ffb75e6489 100644
--- 
a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Operation.java
+++ 
b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Operation.java
@@ -168,7 +168,7 @@ public class Operation extends SwaggerElement {
        private List<ParameterInfo> parameters;
        private List<Map<String,List<String>>> security;
 
-       private Map<String,ResponseInfo> responses;
+       private Map<String,ResponseInfo> responses = map();
 
        /**
         * Default constructor.
@@ -200,12 +200,8 @@ public class Operation extends SwaggerElement {
                        copyFrom.parameters.forEach(x -> 
this.parameters.add(x.copy()));
                }
 
-               if (copyFrom.responses == null) {
-                       this.responses = null;
-               } else {
-                       this.responses = map();
-                       copyFrom.responses.forEach((k, v) -> 
this.responses.put(k, v.copy()));
-               }
+               if (nn(copyFrom.responses))
+                       copyFrom.responses.forEach((k, v) -> responses.put(k, 
v.copy()));
 
                if (copyFrom.security == null) {
                        this.security = null;
@@ -322,7 +318,7 @@ public class Operation extends SwaggerElement {
        public Operation addResponse(String statusCode, ResponseInfo response) {
                assertArgNotNull("statusCode", statusCode);
                assertArgNotNull("response", response);
-               responses = mapb(String.class, 
ResponseInfo.class).to(responses).add(statusCode, response).build();
+               responses.put(statusCode, response);
                return this;
        }
 
@@ -577,7 +573,7 @@ public class Operation extends SwaggerElement {
         */
        public ResponseInfo getResponse(String status) {
                assertArgNotNull("status", status);
-               return responses == null ? null : responses.get(status);
+               return responses.get(status);
        }
 
        /**
@@ -588,7 +584,7 @@ public class Operation extends SwaggerElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,ResponseInfo> getResponses() { return responses; }
+       public Map<String,ResponseInfo> getResponses() { return 
nullIfEmpty(responses); }
 
        /**
         * Bean property getter:  <property>schemes</property>.
@@ -652,7 +648,7 @@ public class Operation extends SwaggerElement {
                        .addIf(nn(operationId), "operationId")
                        .addIf(nn(parameters), "parameters")
                        .addIf(nn(produces), "produces")
-                       .addIf(nn(responses), "responses")
+                       .addIf(isNotEmpty(responses), "responses")
                        .addIf(nn(schemes), "schemes")
                        .addIf(nn(security), "security")
                        .addIf(nn(summary), "summary")
@@ -863,7 +859,9 @@ public class Operation extends SwaggerElement {
         * @return This object.
         */
        public Operation setResponses(Map<String,ResponseInfo> value) {
-               responses = copyOf(value);
+               responses.clear();
+               if (nn(value))
+                       responses.putAll(value);
                return this;
        }
 
diff --git 
a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/ResponseInfo.java
 
b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/ResponseInfo.java
index 71759aca05..05c898fc46 100644
--- 
a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/ResponseInfo.java
+++ 
b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/ResponseInfo.java
@@ -84,8 +84,8 @@ public class ResponseInfo extends SwaggerElement {
 
        private String description;
        private SchemaInfo schema;
-       private Map<String,HeaderInfo> headers;
-       private Map<String,Object> examples;
+       private Map<String,HeaderInfo> headers = map();
+       private Map<String,Object> examples = map();
 
        /**
         * Default constructor.
@@ -102,8 +102,10 @@ public class ResponseInfo extends SwaggerElement {
 
                this.description = copyFrom.description;
                this.schema = copyFrom.schema == null ? null : 
copyFrom.schema.copy();
-               this.examples = copyOf(copyFrom.examples);
-               this.headers = copyOf(copyFrom.headers, HeaderInfo::copy);
+               if (nn(copyFrom.examples))
+                       examples.putAll(copyOf(copyFrom.examples));
+               if (nn(copyFrom.headers))
+                       headers.putAll(copyOf(copyFrom.headers, 
HeaderInfo::copy));
        }
 
        /**
@@ -119,7 +121,7 @@ public class ResponseInfo extends SwaggerElement {
        public ResponseInfo addExample(String mimeType, Object example) {
                assertArgNotNull("mimeType", mimeType);
                assertArgNotNull("example", example);
-               examples = mapb(String.class, 
Object.class).to(examples).sparse().add(mimeType, example).build();
+               examples.put(mimeType, example);
                return this;
        }
 
@@ -133,7 +135,7 @@ public class ResponseInfo extends SwaggerElement {
        public ResponseInfo addHeader(String name, HeaderInfo header) {
                assertArgNotNull("name", name);
                assertArgNotNull("header", header);
-               headers = mapb(String.class, 
HeaderInfo.class).to(headers).add(name, header).build();
+               headers.put(name, header);
                return this;
        }
 
@@ -198,7 +200,7 @@ public class ResponseInfo extends SwaggerElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,Object> getExamples() { return examples; }
+       public Map<String,Object> getExamples() { return nullIfEmpty(examples); 
}
 
        /**
         * Returns the header information with the specified name.
@@ -208,7 +210,7 @@ public class ResponseInfo extends SwaggerElement {
         */
        public HeaderInfo getHeader(String name) {
                assertArgNotNull("name", name);
-               return headers == null ? null : headers.get(name);
+               return headers.get(name);
        }
 
        /**
@@ -219,7 +221,7 @@ public class ResponseInfo extends SwaggerElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,HeaderInfo> getHeaders() { return headers; }
+       public Map<String,HeaderInfo> getHeaders() { return 
nullIfEmpty(headers); }
 
        /**
         * Bean property getter:  <property>schema</property>.
@@ -236,8 +238,8 @@ public class ResponseInfo extends SwaggerElement {
                // @formatter:off
                var s = setb(String.class)
                        .addIf(nn(description), "description")
-                       .addIf(nn(examples), "examples")
-                       .addIf(nn(headers), "headers")
+                       .addIf(isNotEmpty(examples), "examples")
+                       .addIf(isNotEmpty(headers), "headers")
                        .addIf(nn(schema), "schema")
                        .build();
                // @formatter:on
@@ -262,8 +264,7 @@ public class ResponseInfo extends SwaggerElement {
                if (nn(schema))
                        schema = schema.resolveRefs(swagger, refStack, 
maxDepth);
 
-               if (nn(headers))
-                       headers.entrySet().forEach(x -> 
x.setValue(x.getValue().resolveRefs(swagger, refStack, maxDepth)));
+               headers.entrySet().forEach(x -> 
x.setValue(x.getValue().resolveRefs(swagger, refStack, maxDepth)));
 
                return this;
        }
@@ -314,7 +315,9 @@ public class ResponseInfo extends SwaggerElement {
         * @return This object.
         */
        public ResponseInfo setExamples(Map<String,Object> value) {
-               examples = copyOf(value);
+               examples.clear();
+               if (nn(value))
+                       examples.putAll(value);
                return this;
        }
 
@@ -330,7 +333,9 @@ public class ResponseInfo extends SwaggerElement {
         * @return This object.
         */
        public ResponseInfo setHeaders(Map<String,HeaderInfo> value) {
-               headers = copyOf(value);
+               headers.clear();
+               if (nn(value))
+                       headers.putAll(value);
                return this;
        }
 
diff --git 
a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/SchemaInfo.java
 
b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/SchemaInfo.java
index 6b3f756fb9..f197c4bb4c 100644
--- 
a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/SchemaInfo.java
+++ 
b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/SchemaInfo.java
@@ -110,7 +110,7 @@ public class SchemaInfo extends SwaggerElement {
        private Set<Object> _enum;  // NOSONAR - Intentional naming.
        private Set<SchemaInfo> allOf;
        private Set<String> requiredProperties;
-       private Map<String,SchemaInfo> properties;
+       private Map<String,SchemaInfo> properties = map();
        private SchemaInfo additionalProperties;
 
        /**
@@ -156,7 +156,8 @@ public class SchemaInfo extends SwaggerElement {
                this.type = copyFrom.type;
                this.uniqueItems = copyFrom.uniqueItems;
                this.xml = copyFrom.xml == null ? null : copyFrom.xml.copy();
-               this.properties = copyOf(copyFrom.properties, SchemaInfo::copy);
+               if (nn(copyFrom.properties))
+                       properties.putAll(copyOf(copyFrom.properties, 
SchemaInfo::copy));
        }
 
        /**
@@ -227,7 +228,7 @@ public class SchemaInfo extends SwaggerElement {
        public SchemaInfo addProperty(String key, SchemaInfo value) {
                assertArgNotNull("key", key);
                assertArgNotNull("value", value);
-               properties = mapb(String.class, 
SchemaInfo.class).to(properties).sparse().add(key, value).build();
+               properties.put(key, value);
                return this;
        }
 
@@ -473,7 +474,7 @@ public class SchemaInfo extends SwaggerElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,SchemaInfo> getProperties() { return properties; }
+       public Map<String,SchemaInfo> getProperties() { return 
nullIfEmpty(properties); }
 
        /**
         * Bean property getter:  <property>readOnly</property>.
@@ -561,7 +562,7 @@ public class SchemaInfo extends SwaggerElement {
                        .addIf(nn(minProperties), "minProperties")
                        .addIf(nn(multipleOf), "multipleOf")
                        .addIf(nn(pattern), "pattern")
-                       .addIf(nn(properties), "properties")
+                       .addIf(isNotEmpty(properties), "properties")
                        .addIf(nn(readOnly), "readOnly")
                        .addIf(nn(ref), "$ref")
                        .addIf(nn(required), "required")
@@ -602,8 +603,7 @@ public class SchemaInfo extends SwaggerElement {
                if (nn(items))
                        items = items.resolveRefs(swagger, refStack, maxDepth);
 
-               if (nn(properties))
-                       properties.entrySet().forEach(x -> 
x.setValue(x.getValue().resolveRefs(swagger, refStack, maxDepth)));
+               properties.entrySet().forEach(x -> 
x.setValue(x.getValue().resolveRefs(swagger, refStack, maxDepth)));
 
                if (nn(additionalProperties))
                        additionalProperties = 
additionalProperties.resolveRefs(swagger, refStack, maxDepth);
@@ -994,7 +994,9 @@ public class SchemaInfo extends SwaggerElement {
         * @return This object.
         */
        public SchemaInfo setProperties(Map<String,SchemaInfo> value) {
-               properties = copyOf(value);
+               properties.clear();
+               if (nn(value))
+                       properties.putAll(value);
                return this;
        }
 
diff --git 
a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/SecurityScheme.java
 
b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/SecurityScheme.java
index cd648dde36..68977c05f1 100644
--- 
a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/SecurityScheme.java
+++ 
b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/SecurityScheme.java
@@ -86,7 +86,7 @@ public class SecurityScheme extends SwaggerElement {
        private static final String[] VALID_TYPES = { "basic", "apiKey", 
"oauth2" };
 
        private String type, description, name, in, flow, authorizationUrl, 
tokenUrl;
-       private Map<String,String> scopes;
+       private Map<String,String> scopes = map();
 
        /**
         * Default constructor.
@@ -106,7 +106,8 @@ public class SecurityScheme extends SwaggerElement {
                this.flow = copyFrom.flow;
                this.in = copyFrom.in;
                this.name = copyFrom.name;
-               this.scopes = copyOf(copyFrom.scopes);
+               if (nn(copyFrom.scopes))
+                       scopes.putAll(copyFrom.scopes);
                this.tokenUrl = copyFrom.tokenUrl;
                this.type = copyFrom.type;
        }
@@ -124,7 +125,7 @@ public class SecurityScheme extends SwaggerElement {
        public SecurityScheme addScope(String key, String value) {
                assertArgNotNull("key", key);
                assertArgNotNull("value", value);
-               scopes = mapb(String.class, 
String.class).to(scopes).sparse().add(key, value).build();
+               scopes.put(key, value);
                return this;
        }
 
@@ -211,7 +212,7 @@ public class SecurityScheme extends SwaggerElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,String> getScopes() { return scopes; }
+       public Map<String,String> getScopes() { return nullIfEmpty(scopes); }
 
        /**
         * Bean property getter:  <property>tokenUrl</property>.
@@ -242,7 +243,7 @@ public class SecurityScheme extends SwaggerElement {
                        .addIf(nn(flow), "flow")
                        .addIf(nn(in), "in")
                        .addIf(nn(name), "name")
-                       .addIf(nn(scopes), "scopes")
+                       .addIf(isNotEmpty(scopes), "scopes")
                        .addIf(nn(tokenUrl), "tokenUrl")
                        .addIf(nn(type), "type")
                        .build();
@@ -374,7 +375,9 @@ public class SecurityScheme extends SwaggerElement {
         * @return This object.
         */
        public SecurityScheme setScopes(Map<String,String> value) {
-               scopes = copyOf(value);
+               scopes.clear();
+               if (nn(value))
+                       scopes.putAll(value);
                return this;
        }
 
diff --git 
a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Swagger.java
 
b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Swagger.java
index 36fb944213..9d9fd36c2f 100644
--- 
a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Swagger.java
+++ 
b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Swagger.java
@@ -101,12 +101,12 @@ public class Swagger extends SwaggerElement {
        private Set<MediaType> consumes, produces;
        private Set<Tag> tags;
        private List<Map<String,List<String>>> security;
-       private Map<String,JsonMap> definitions;
-       private Map<String,ParameterInfo> parameters;
-       private Map<String,ResponseInfo> responses;
-       private Map<String,SecurityScheme> securityDefinitions;
+       private Map<String,JsonMap> definitions = map();
+       private Map<String,ParameterInfo> parameters = map();
+       private Map<String,ResponseInfo> responses = map();
+       private Map<String,SecurityScheme> securityDefinitions = map();
 
-       private Map<String,OperationMap> paths;
+       private Map<String,OperationMap> paths = new TreeMap<>(PATH_COMPARATOR);
 
        /**
         * Default constructor.
@@ -131,17 +131,22 @@ public class Swagger extends SwaggerElement {
                this.swagger = copyFrom.swagger;
 
                // TODO - Definitions are not deep copied, so they should not 
contain references.
-               this.definitions = copyOf(copyFrom.definitions, JsonMap::new);
-
-               this.paths = copyOf(copyFrom.paths, v -> {
-                       var m = new OperationMap();
-                       v.forEach((k2, v2) -> m.put(k2, v2.copy()));
-                       return m;
-               });
-
-               this.parameters = copyOf(copyFrom.parameters, 
ParameterInfo::copy);
-               this.responses = copyOf(copyFrom.responses, ResponseInfo::copy);
-               this.securityDefinitions = copyOf(copyFrom.securityDefinitions, 
SecurityScheme::copy);
+               if (nn(copyFrom.definitions))
+                       definitions.putAll(copyOf(copyFrom.definitions, 
JsonMap::new));
+
+               if (nn(copyFrom.paths))
+                       copyFrom.paths.forEach((k, v) -> {
+                               var m = new OperationMap();
+                               v.forEach((k2, v2) -> m.put(k2, v2.copy()));
+                               paths.put(k, m);
+                       });
+
+               if (nn(copyFrom.parameters))
+                       parameters.putAll(copyOf(copyFrom.parameters, 
ParameterInfo::copy));
+               if (nn(copyFrom.responses))
+                       responses.putAll(copyOf(copyFrom.responses, 
ResponseInfo::copy));
+               if (nn(copyFrom.securityDefinitions))
+                       
securityDefinitions.putAll(copyOf(copyFrom.securityDefinitions, 
SecurityScheme::copy));
 
                this.security = copyOf(copyFrom.security, x -> {
                        Map<String,List<String>> m2 = map();
@@ -198,7 +203,7 @@ public class Swagger extends SwaggerElement {
        public Swagger addDefinition(String name, JsonMap schema) {
                assertArgNotNull("name", name);
                assertArgNotNull("schema", schema);
-               definitions = mapb(String.class, 
JsonMap.class).to(definitions).sparse().add(name, schema).build();
+               definitions.put(name, schema);
                return this;
        }
 
@@ -215,7 +220,7 @@ public class Swagger extends SwaggerElement {
        public Swagger addParameter(String name, ParameterInfo parameter) {
                assertArgNotNull("name", name);
                assertArgNotNull("parameter", parameter);
-               parameters = mapb(String.class, 
ParameterInfo.class).to(parameters).sparse().add(name, parameter).build();
+               parameters.put(name, parameter);
                return this;
        }
 
@@ -234,9 +239,7 @@ public class Swagger extends SwaggerElement {
                assertArgNotNull("path", path);
                assertArgNotNull("methodName", methodName);
                assertArgNotNull("operation", operation);
-               if (paths == null)
-                       paths = new TreeMap<>(PATH_COMPARATOR);
-               getPaths().computeIfAbsent(path, k -> new 
OperationMap()).put(methodName, operation);
+               paths.computeIfAbsent(path, k -> new 
OperationMap()).put(methodName, operation);
                return this;
        }
 
@@ -287,7 +290,7 @@ public class Swagger extends SwaggerElement {
        public Swagger addResponse(String name, ResponseInfo response) {
                assertArgNotNull("name", name);
                assertArgNotNull("response", response);
-               responses = mapb(String.class, 
ResponseInfo.class).to(responses).sparse().add(name, response).build();
+               responses.put(name, response);
                return this;
        }
 
@@ -387,7 +390,7 @@ public class Swagger extends SwaggerElement {
        public Swagger addSecurityDefinition(String name, SecurityScheme 
securityScheme) {
                assertArgNotNull("name", name);
                assertArgNotNull("securityScheme", securityScheme);
-               securityDefinitions = mapb(String.class, 
SecurityScheme.class).to(securityDefinitions).sparse().add(name, 
securityScheme).build();
+               securityDefinitions.put(name, securityScheme);
                return this;
        }
 
@@ -519,7 +522,7 @@ public class Swagger extends SwaggerElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,JsonMap> getDefinitions() { return definitions; }
+       public Map<String,JsonMap> getDefinitions() { return 
nullIfEmpty(definitions); }
 
        /**
         * Bean property getter:  <property>externalDocs</property>.
@@ -588,7 +591,7 @@ public class Swagger extends SwaggerElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,ParameterInfo> getParameters() { return parameters; }
+       public Map<String,ParameterInfo> getParameters() { return 
nullIfEmpty(parameters); }
 
        /**
         * Shortcut for calling <c>getPaths().get(path);</c>
@@ -609,7 +612,7 @@ public class Swagger extends SwaggerElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,OperationMap> getPaths() { return paths; }
+       public Map<String,OperationMap> getPaths() { return nullIfEmpty(paths); 
}
 
        /**
         * Bean property getter:  <property>produces</property>.
@@ -656,7 +659,7 @@ public class Swagger extends SwaggerElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,ResponseInfo> getResponses() { return responses; }
+       public Map<String,ResponseInfo> getResponses() { return 
nullIfEmpty(responses); }
 
        /**
         * Bean property getter:  <property>schemes</property>.
@@ -686,7 +689,7 @@ public class Swagger extends SwaggerElement {
         *
         * @return The property value, or <jk>null</jk> if it is not set.
         */
-       public Map<String,SecurityScheme> getSecurityDefinitions() { return 
securityDefinitions; }
+       public Map<String,SecurityScheme> getSecurityDefinitions() { return 
nullIfEmpty(securityDefinitions); }
 
        /**
         * Bean property getter:  <property>swagger</property>.
@@ -714,17 +717,17 @@ public class Swagger extends SwaggerElement {
                var s = setb(String.class)
                        .addIf(nn(basePath), "basePath")
                        .addIf(nn(consumes), "consumes")
-                       .addIf(nn(definitions), "definitions")
+                       .addIf(isNotEmpty(definitions), "definitions")
                        .addIf(nn(externalDocs), "externalDocs")
                        .addIf(nn(host), "host")
                        .addIf(nn(info), "info")
-                       .addIf(nn(parameters), "parameters")
-                       .addIf(nn(paths), "paths")
+                       .addIf(isNotEmpty(parameters), "parameters")
+                       .addIf(isNotEmpty(paths), "paths")
                        .addIf(nn(produces), "produces")
-                       .addIf(nn(responses), "responses")
+                       .addIf(isNotEmpty(responses), "responses")
                        .addIf(nn(schemes), "schemes")
                        .addIf(nn(security), "security")
-                       .addIf(nn(securityDefinitions), "securityDefinitions")
+                       .addIf(isNotEmpty(securityDefinitions), 
"securityDefinitions")
                        .addIf(nn(swagger), "swagger")
                        .addIf(nn(tags), "tags")
                        .build();
@@ -822,7 +825,9 @@ public class Swagger extends SwaggerElement {
         * @return This object.
         */
        public Swagger setDefinitions(Map<String,JsonMap> value) {
-               definitions = copyOf(value);
+               definitions.clear();
+               if (nn(value))
+                       definitions.putAll(value);
                return this;
        }
 
@@ -891,7 +896,9 @@ public class Swagger extends SwaggerElement {
         * @return This object.
         */
        public Swagger setParameters(Map<String,ParameterInfo> value) {
-               parameters = copyOf(value);
+               parameters.clear();
+               if (nn(value))
+                       parameters.putAll(value);
                return this;
        }
 
@@ -908,7 +915,9 @@ public class Swagger extends SwaggerElement {
         * @return This object.
         */
        public Swagger setPaths(Map<String,OperationMap> value) {
-               paths = mapb(String.class, 
OperationMap.class).sparse().sorted(PATH_COMPARATOR).addAll(value).build();
+               paths.clear();
+               if (nn(value))
+                       paths.putAll(value);
                return this;
        }
 
@@ -956,7 +965,9 @@ public class Swagger extends SwaggerElement {
         * @return This object.
         */
        public Swagger setResponses(Map<String,ResponseInfo> value) {
-               responses = copyOf(value);
+               responses.clear();
+               if (nn(value))
+                       responses.putAll(value);
                return this;
        }
 
@@ -1027,7 +1038,9 @@ public class Swagger extends SwaggerElement {
         * @return This object.
         */
        public Swagger setSecurityDefinitions(Map<String,SecurityScheme> value) 
{
-               securityDefinitions = copyOf(value);
+               securityDefinitions.clear();
+               if (nn(value))
+                       securityDefinitions.putAll(value);
                return this;
        }
 
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredList.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredList.java
index f5ceac29e2..9013582974 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredList.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredList.java
@@ -485,7 +485,6 @@ public class FilteredList<E> extends AbstractList<E> {
        }
 
        @Override
-       @SuppressWarnings("unchecked")
        public <T> T[] toArray(T[] a) {
                return list.toArray(a);
        }
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredSet.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredSet.java
index b57db45912..0fa6d387fb 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredSet.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredSet.java
@@ -432,7 +432,6 @@ public class FilteredSet<E> extends AbstractSet<E> {
        }
 
        @Override
-       @SuppressWarnings("unchecked")
        public <T> T[] toArray(T[] a) {
                return set.toArray(a);
        }
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/MapBuilder.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/MapBuilder.java
index 6073bda4e9..24b0d095b2 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/MapBuilder.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/MapBuilder.java
@@ -579,20 +579,6 @@ public class MapBuilder<K,V> {
                return this;
        }
 
-       /**
-        * Specifies the map to append to.
-        *
-        * <p>
-        * If not specified, uses a new {@link HashMap} (or {@link 
LinkedHashMap} if {@link #ordered()} is set).
-        *
-        * @param map The map to append to.
-        * @return This object.
-        */
-       public MapBuilder<K,V> to(Map<K,V> map) {
-               this.map = map;
-               return this;
-       }
-
        /**
         * When specified, {@link #build()} will return an unmodifiable map.
         *
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/ResettableSupplier.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/ResettableSupplier.java
index 98b4022039..60f7e5a8ac 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/ResettableSupplier.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/ResettableSupplier.java
@@ -150,4 +150,33 @@ public class ResettableSupplier<T> implements 
OptionalSupplier<T> {
        public void set(T value) {
                cache.set(opt(value));
        }
+
+       /**
+        * Returns <jk>true</jk> if the supplier has not yet been called (cache 
is empty).
+        *
+        * <p>
+        * This method checks whether the cached value is <jk>null</jk>, which 
indicates that
+        * {@link #get()} has not yet been called, or the cache was reset.
+        *
+        * @return <jk>true</jk> if the supplier has not been called yet, 
<jk>false</jk> if a value has been cached.
+        */
+       public boolean isSupplied() {
+               return cache.get() == null;
+       }
+
+       /**
+        * Creates a copy of this supplier.
+        *
+        * <p>
+        * If a value has been cached, the copy will use a supplier that 
returns that cached value.
+        * If no value has been cached yet, the copy will use the original 
supplier.
+        *
+        * @return A new {@link ResettableSupplier} instance with the same 
state as this supplier.
+        */
+       public ResettableSupplier<T> copy() {
+               Optional<T> o = cache.get();
+               if (o == null)
+                       return new ResettableSupplier<>(supplier);
+               return new ResettableSupplier<>(()->o.get());
+       }
 }
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/io/LocalDir.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/io/LocalDir.java
index 4ebebe3b89..c59ef4dd90 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/io/LocalDir.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/io/LocalDir.java
@@ -23,8 +23,6 @@ import static org.apache.juneau.commons.utils.Utils.*;
 import java.net.*;
 import java.nio.file.*;
 
-import org.apache.juneau.commons.utils.*;
-
 /**
  * Represents a directory that can be located either on the classpath or in 
the file system.
  *
@@ -144,7 +142,7 @@ public class LocalDir {
         */
        public LocalDir(Class<?> clazz, String clazzPath) {
                this.clazz = assertArgNotNull("clazz", clazz);
-               this.clazzPath = "/".equals(clazzPath) ? "/" : 
StringUtils.nullIfEmpty(trimTrailingSlashes(clazzPath));
+               this.clazzPath = "/".equals(clazzPath) ? "/" : 
nullIfEmpty(trimTrailingSlashes(clazzPath));
                this.path = null;
                this.hashCode = hash(clazz, clazzPath);
        }
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/StringUtils.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/StringUtils.java
index 7f1f616d0c..44dabe0153 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/StringUtils.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/StringUtils.java
@@ -4868,16 +4868,6 @@ public class StringUtils {
                return ! containsAny(s, values);
        }
 
-       /**
-        * Returns the specified string, or <jk>null</jk> if that string is 
<jk>null</jk> or empty.
-        *
-        * @param value The string value to check.
-        * @return The string value, or <jk>null</jk> if the string is 
<jk>null</jk> or empty.
-        */
-       public static String nullIfEmpty(String value) {
-               return isEmpty(value) ? null : value;
-       }
-
        /**
         * Returns an obfuscated version of the specified string.
         *
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java
index da7b7afc7a..bc34615325 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java
@@ -19,7 +19,6 @@ package org.apache.juneau.commons.utils;
 import static org.apache.juneau.commons.utils.AssertionUtils.*;
 import static org.apache.juneau.commons.utils.StringUtils.*;
 import static org.apache.juneau.commons.utils.ThrowableUtils.*;
-
 import java.lang.reflect.*;
 import java.nio.charset.*;
 import java.text.*;
@@ -1001,11 +1000,46 @@ public class Utils {
                return value != null;
        }
 
+       /**
+        * Returns <jk>true</jk> if the specified object is <jk>null</jk>.
+        *
+        * <p>
+        * Equivalent to <c><jv>value</jv> == <jk>null</jk></c>, but with a 
more readable method name.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      <jk>if</jk> (<jsm>isNull</jsm>(<jv>myObject</jv>)) {
+        *              <jc>// Handle null case</jc>
+        *      }
+        * </p>
+        *
+        * @param <T> The object type.
+        * @param value The object to check.
+        * @return <jk>true</jk> if the specified object is <jk>null</jk>.
+        * @see #isNotNull(Object)
+        * @see #nn(Object)
+        */
        public static <T> boolean isNull(T value) {
                return value == null;
        }
 
-       public static <T> boolean isAllNull(T...values) {
+       /**
+        * Returns <jk>true</jk> if all specified values are <jk>null</jk>.
+        *
+        * <p>
+        * If the values array itself is <jk>null</jk>, returns <jk>true</jk>.
+        * If any value in the array is not <jk>null</jk>, returns 
<jk>false</jk>.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      <jk>boolean</jk> <jv>allNull</jv> = 
<jsm>isAllNull</jsm>(<jk>null</jk>, <jk>null</jk>, <jk>null</jk>);  <jc>// 
true</jc>
+        *      <jk>boolean</jk> <jv>notAllNull</jv> = 
<jsm>isAllNull</jsm>(<jk>null</jk>, <js>"value"</js>, <jk>null</jk>);  <jc>// 
false</jc>
+        * </p>
+        *
+        * @param values The values to check.
+        * @return <jk>true</jk> if all values are <jk>null</jk> (or the array 
is <jk>null</jk>), <jk>false</jk> otherwise.
+        */
+       public static boolean isAllNull(Object...values) {
                if (values == null) return true;
                for (var v : values)
                        if (v != null)
@@ -1192,6 +1226,7 @@ public class Utils {
         * @return <jk>true</jk> if the objects are not equal.
         * @see #eq(Object, Object)
         */
+       // TODO - Rename this to neq, then add a ne for not-empty
        public static <T> boolean ne(T s1, T s2) {
                return ! eq(s1, s2);
        }
@@ -1218,6 +1253,7 @@ public class Utils {
         * @return <jk>true</jk> if the objects are not equal based on the 
test, or if one is <jk>null</jk> and the other is not.
         * @see #eq(Object, Object, BiPredicate)
         */
+       // TODO - Rename this to neq, then add a ne for not-empty
        public static <T,U> boolean ne(T o1, U o2, BiPredicate<T,U> test) {
                if (o1 == null)
                        return nn(o2);
@@ -1247,6 +1283,7 @@ public class Utils {
         * @return <jk>true</jk> if the strings are not equal ignoring case.
         * @see #eqic(String, String)
         */
+       // TODO - Rename this to neqic, then add a ne for not-empty
        public static boolean neic(String s1, String s2) {
                return ! eqic(s1, s2);
        }
@@ -1270,7 +1307,7 @@ public class Utils {
         * @return <jk>true</jk> if the specified object is not <jk>null</jk>.
         */
        public static boolean nn(Object o) {
-               return isNotNull(o);
+               return o != null;
        }
 
        /**
@@ -1713,4 +1750,61 @@ public class Utils {
 
        /** Constructor - This class is meant to be subclasses. */
        protected Utils() {}
+
+       /**
+        * Returns the specified string, or <jk>null</jk> if that string is 
<jk>null</jk> or empty.
+        *
+        * @param value The string value to check.
+        * @return The string value, or <jk>null</jk> if the string is 
<jk>null</jk> or empty.
+        */
+       public static String nullIfEmpty(String value) {
+               return StringUtils.isEmpty(value) ? null : value;
+       }
+
+       /**
+        * Returns <jk>null</jk> if the specified map is <jk>null</jk> or 
empty, otherwise returns the map.
+        *
+        * <p>
+        * This is a convenience method for preserving backward compatibility 
when maps are initialized immediately
+        * but getters should return <jk>null</jk> if the map is empty.
+        *
+        * @param <K> The key type.
+        * @param <V> The value type.
+        * @param val The map to check.
+        * @return <jk>null</jk> if the map is <jk>null</jk> or empty, 
otherwise the map itself.
+        */
+       public static <K,V> Map<K,V> nullIfEmpty(Map<K,V> val) {
+               return isEmpty(val) ? null : val;
+       }
+
+       /**
+        * Returns <jk>null</jk> if the specified list is <jk>null</jk> or 
empty, otherwise returns the list.
+        *
+        * <p>
+        * This is a convenience method for preserving backward compatibility 
when lists are initialized immediately
+        * but getters should return <jk>null</jk> if the list is empty.
+        *
+        * @param <E> The element type.
+        * @param val The list to check.
+        * @return <jk>null</jk> if the list is <jk>null</jk> or empty, 
otherwise the list itself.
+        */
+       public static <E> List<E> nullIfEmpty(List<E> val) {
+               return isEmpty(val) ? null : val;
+       }
+
+       /**
+        * Returns <jk>null</jk> if the specified set is <jk>null</jk> or 
empty, otherwise returns the set.
+        *
+        * <p>
+        * This is a convenience method for preserving backward compatibility 
when sets are initialized immediately
+        * but getters should return <jk>null</jk> if the set is empty.
+        *
+        * @param <E> The element type.
+        * @param val The set to check.
+        * @return <jk>null</jk> if the set is <jk>null</jk> or empty, 
otherwise the set itself.
+        */
+       public static <E> Set<E> nullIfEmpty(Set<E> val) {
+               return isEmpty(val) ? null : val;
+       }
+
 }
\ No newline at end of file
diff --git 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java 
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
index 33d8550ea9..a7a6d13e29 100644
--- 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
+++ 
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
@@ -32,7 +32,6 @@ import org.apache.juneau.*;
 import org.apache.juneau.collections.*;
 import org.apache.juneau.commons.collections.*;
 import org.apache.juneau.commons.function.*;
-import org.apache.juneau.commons.utils.*;
 import org.apache.juneau.config.event.*;
 import org.apache.juneau.config.internal.*;
 import org.apache.juneau.config.mod.*;
@@ -980,7 +979,7 @@ public class Config extends Context implements 
ConfigEventListener {
                assertArgNotNull("key", key);
                var sname = sname(key);
                var skey = skey(key);
-               modifiers = StringUtils.nullIfEmpty(modifiers);
+               modifiers = nullIfEmpty(modifiers);
 
                var s = applyMods(modifiers, serialize(value, serializer));
 
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/UriContext.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/UriContext.java
index 9b3cb3f023..41aa1cf640 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/UriContext.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/UriContext.java
@@ -18,10 +18,10 @@ package org.apache.juneau;
 
 import static org.apache.juneau.commons.utils.StringUtils.*;
 import static org.apache.juneau.commons.utils.ThrowableUtils.*;
+import static org.apache.juneau.commons.utils.Utils.*;
 
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.collections.*;
-import org.apache.juneau.commons.utils.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
 
@@ -123,10 +123,10 @@ public class UriContext {
         */
        public UriContext(String s) throws ParseException {
                var m = JsonMap.ofJson(s);
-               this.authority = 
StringUtils.nullIfEmpty(trimSlashes(m.getString("authority")));
-               this.contextRoot = 
StringUtils.nullIfEmpty(trimSlashes(m.getString("contextRoot")));
-               this.servletPath = 
StringUtils.nullIfEmpty(trimSlashes(m.getString("servletPath")));
-               this.pathInfo = 
StringUtils.nullIfEmpty(trimSlashes(m.getString("pathInfo")));
+               this.authority = 
nullIfEmpty(trimSlashes(m.getString("authority")));
+               this.contextRoot = 
nullIfEmpty(trimSlashes(m.getString("contextRoot")));
+               this.servletPath = 
nullIfEmpty(trimSlashes(m.getString("servletPath")));
+               this.pathInfo = 
nullIfEmpty(trimSlashes(m.getString("pathInfo")));
                this.parentPath = this.pathInfo == null || 
this.pathInfo.indexOf('/') == -1 ? null : this.pathInfo.substring(0, 
this.pathInfo.lastIndexOf('/'));
        }
 
@@ -150,10 +150,10 @@ public class UriContext {
         */
        @Beanc
        public UriContext(@Name("authority") String authority, 
@Name("contextRoot") String contextRoot, @Name("servletPath") String 
servletPath, @Name("pathInfo") String pathInfo) {
-               this.authority = 
StringUtils.nullIfEmpty(trimSlashes(authority));
-               this.contextRoot = 
StringUtils.nullIfEmpty(trimSlashes(contextRoot));
-               this.servletPath = 
StringUtils.nullIfEmpty(trimSlashes(servletPath));
-               this.pathInfo = StringUtils.nullIfEmpty(trimSlashes(pathInfo));
+               this.authority = nullIfEmpty(trimSlashes(authority));
+               this.contextRoot = nullIfEmpty(trimSlashes(contextRoot));
+               this.servletPath = nullIfEmpty(trimSlashes(servletPath));
+               this.pathInfo = nullIfEmpty(trimSlashes(pathInfo));
                this.parentPath = this.pathInfo == null || 
this.pathInfo.indexOf('/') == -1 ? null : this.pathInfo.substring(0, 
this.pathInfo.lastIndexOf('/'));
        }
 
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanStoreEntry.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanStoreEntry.java
index 1ef782271c..f523aa4b3a 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanStoreEntry.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanStoreEntry.java
@@ -18,12 +18,12 @@ package org.apache.juneau.cp;
 
 import static org.apache.juneau.collections.JsonMap.*;
 import static org.apache.juneau.commons.utils.AssertionUtils.*;
-import static org.apache.juneau.commons.utils.StringUtils.*;
 import static org.apache.juneau.commons.utils.Utils.*;
 
 import java.util.function.*;
 
 import org.apache.juneau.collections.*;
+import org.apache.juneau.commons.utils.*;
 
 /**
  * Represents a bean in a {@link BeanStore}.
@@ -110,7 +110,7 @@ public class BeanStoreEntry<T> {
         * @return <jk>true</jk> if this bean is exactly of the specified type 
and has the specified name.
         */
        public boolean matches(Class<?> type, String name) {
-               name = nullIfEmpty(name);
+               name = Utils.nullIfEmpty(name);
                return matches(type) && eq(this.name, name);
        }
 
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteOperationMeta.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteOperationMeta.java
index c924c247c9..bcca0f1716 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteOperationMeta.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteOperationMeta.java
@@ -95,7 +95,7 @@ public class RemoteOperationMeta {
                        }
 
                        if (path.isEmpty()) {
-                               path = HttpUtils.detectHttpPath(m, 
StringUtils.nullIfEmpty(httpMethod));
+                               path = HttpUtils.detectHttpPath(m, 
nullIfEmpty(httpMethod));
                        }
                        if (httpMethod.isEmpty())
                                httpMethod = HttpUtils.detectHttpMethod(m, 
true, defaultMethod);
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 2d3a1c350d..98e44a9a4d 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -5143,7 +5143,7 @@ public class RestContext extends Context {
                                var uppm = pathMatcher.match(upi2);
                                if (nn(uppm) && ! uppm.hasEmptyVars()) {
                                        sb.pathVars(uppm.getVars());
-                                       sb.req(new 
OverrideableHttpServletRequest(sb.req()).pathInfo(StringUtils.nullIfEmpty(urlDecode(uppm.getSuffix()))).servletPath(uppm.getPrefix()));
+                                       sb.req(new 
OverrideableHttpServletRequest(sb.req()).pathInfo(nullIfEmpty(urlDecode(uppm.getSuffix()))).servletPath(uppm.getPrefix()));
                                } else {
                                        var call = sb.build();
                                        
call.debug(isDebug(call)).status(SC_NOT_FOUND).finish();
@@ -5158,7 +5158,7 @@ public class RestContext extends Context {
                                var rc = childMatch.get().getChildContext();
                                if (! uppm.hasEmptyVars()) {
                                        sb.pathVars(uppm.getVars());
-                                       var childRequest = new 
OverrideableHttpServletRequest(sb.req()).pathInfo(StringUtils.nullIfEmpty(urlDecode(uppm.getSuffix())))
+                                       var childRequest = new 
OverrideableHttpServletRequest(sb.req()).pathInfo(nullIfEmpty(urlDecode(uppm.getSuffix())))
                                                
.servletPath(sb.req().getServletPath() + uppm.getPrefix());
                                        rc.execute(rc.getResource(), 
childRequest, sb.res());
                                } else {
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/UrlPathMatch.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/UrlPathMatch.java
index 14bb810a8a..871186033e 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/UrlPathMatch.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/UrlPathMatch.java
@@ -24,6 +24,7 @@ import static org.apache.juneau.commons.utils.Utils.*;
 import java.util.*;
 
 import org.apache.juneau.commons.collections.*;
+import org.apache.juneau.commons.utils.*;
 
 /**
  * Represents a URL path pattern match.
@@ -67,7 +68,7 @@ public class UrlPathMatch {
                        if (c == -1)
                                c = path.length();
                }
-               return nullIfEmpty(path.substring(0, c));
+               return Utils.nullIfEmpty(path.substring(0, c));
        }
 
        /**
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java
index 98f411e363..a759de616d 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java
@@ -17,7 +17,6 @@
 package org.apache.juneau.rest.widget;
 
 import static org.apache.juneau.commons.utils.IoUtils.*;
-import static org.apache.juneau.commons.utils.StringUtils.*;
 import static org.apache.juneau.commons.utils.ThrowableUtils.*;
 import static org.apache.juneau.commons.utils.Utils.*;
 
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/bean/openapi3/Operation_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/bean/openapi3/Operation_Test.java
index 800bbc93ac..35a2ae5442 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/bean/openapi3/Operation_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/bean/openapi3/Operation_Test.java
@@ -336,7 +336,7 @@ class Operation_Test extends TestBase {
                        assertMapped(
                                TESTER.bean(), (obj,prop) -> cns(obj.get(prop, 
Object.class)),
                                
"callbacks,deprecated,description,externalDocs,operationId,parameters,requestBody,responses,security,servers,summary,tags,x1,x2",
-                               
"FilteredMap,Boolean,String,ExternalDocumentation,String,ArrayList,RequestBodyInfo,FilteredMap,ArrayList,ArrayList,String,ArrayList,String,<null>"
+                               
"LinkedHashMap,Boolean,String,ExternalDocumentation,String,ArrayList,RequestBodyInfo,LinkedHashMap,ArrayList,ArrayList,String,ArrayList,String,<null>"
                        );
                }
 
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/commons/collections/FilteredList_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/FilteredList_Test.java
index 2235972aac..f65f116b89 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/commons/collections/FilteredList_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/FilteredList_Test.java
@@ -144,7 +144,6 @@ class FilteredList_Test extends TestBase {
                list.add(10);
 
                assertSize(2, list);
-               assertTrue(list instanceof FilteredList);
        }
 
        
//====================================================================================================
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/commons/collections/MapBuilder_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/MapBuilder_Test.java
index 090405f55e..f51badb145 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/commons/collections/MapBuilder_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/MapBuilder_Test.java
@@ -281,23 +281,6 @@ class MapBuilder_Test extends TestBase {
        // Copy mode
        
//-----------------------------------------------------------------------------------------------------------------
 
-       @Test
-       void f01_copy() {
-               var original = new LinkedHashMap<String,Integer>();
-               original.put("a", 1);
-
-               var map = MapBuilder.create(String.class, Integer.class)
-                       .to(original)
-                       .add("b", 2)
-                       .copy()
-                       .add("c", 3)
-                       .build();
-
-               assertSize(3, map);
-               assertSize(2, original);  // Original has "a" and "b" added 
before copy()
-               assertNotSame(original, map);  // After copy(), they're 
different maps
-       }
-
        
//-----------------------------------------------------------------------------------------------------------------
        // Complex scenarios
        
//-----------------------------------------------------------------------------------------------------------------
@@ -812,18 +795,6 @@ class MapBuilder_Test extends TestBase {
                assertNull(map);
        }
 
-       @Test
-       void l02_build_sparseWithEmptyMap() {
-               var existing = new LinkedHashMap<String,Integer>();
-
-               var map = MapBuilder.create(String.class, Integer.class)
-                       .to(existing)
-                       .sparse()
-                       .build();
-
-               assertNull(map);
-       }
-
        @Test
        void l03_build_notSparseWithNullMap() {
                var map = MapBuilder.create(String.class, Integer.class)
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/StringUtils_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/StringUtils_Test.java
index c6949cdc82..b3d5e120dc 100755
--- 
a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/StringUtils_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/StringUtils_Test.java
@@ -493,15 +493,15 @@ class StringUtils_Test extends TestBase {
                assertTrue(compare("a", "b") < 0);
                assertTrue(compare("b", "a") > 0);
                assertEquals(0, compare("a", "a"));
-               
+
                // s1 null - covers line 630-631 (returns Integer.MIN_VALUE)
                assertEquals(Integer.MIN_VALUE, compare(null, "b"));
                assertTrue(compare(null, "b") < 0);
-               
+
                // s2 null - covers line 632-633 (returns Integer.MAX_VALUE)
                assertEquals(Integer.MAX_VALUE, compare("b", null));
                assertTrue(compare("b", null) > 0);
-               
+
                // Both null - covers line 628-629
                assertEquals(0, compare(null, null));
        }
@@ -1777,7 +1777,7 @@ class StringUtils_Test extends TestBase {
                assertEquals(1 * h + 30 * m, getDuration("1h 30m"));
                assertEquals(2 * d + 3 * h + 15 * m, getDuration("2d3h15m"));
                assertEquals(1 * w + 2 * d + 3 * h, getDuration("1w2d3h"));
-               assertEquals(-1, getDuration("d10"));  // Non-number before 
unit - covers invalid number branch 
+               assertEquals(-1, getDuration("d10"));  // Non-number before 
unit - covers invalid number branch
 
                // Months
                assertEquals(1 * mo, getDuration("1mo"));
@@ -1913,7 +1913,7 @@ class StringUtils_Test extends TestBase {
                assertTrue(pattern.matcher("test123").matches());
                assertTrue(pattern.matcher("TEST123").matches());
 
-               // Null input should return null 
+               // Null input should return null
                assertNull(getMatchPattern(null));
                assertNull(getMatchPattern(null, 
java.util.regex.Pattern.CASE_INSENSITIVE));
        }
@@ -2493,7 +2493,7 @@ class StringUtils_Test extends TestBase {
                // Code path: firstRealCharacter(s) == -1 (after closing 
bracket)
                assertTrue(isProbablyJsonArray("  [1,2,3]  ", true)); // Valid, 
no characters after ']'
                assertTrue(isProbablyJsonArray("  /*comment*/ [1,2,3] 
/*comment*/  ", true)); // Valid, only comments/whitespace after ']'
-               // Test with newline to ensure the code path is covered 
+               // Test with newline to ensure the code path is covered
                // Code path: c == '\n' branch
                assertTrue(isProbablyJsonArray("  [1,2,3] //comment\n  ", 
true)); // Valid, // comment with newline
                // Code path: c == -1 branch (EOF)
@@ -2541,7 +2541,7 @@ class StringUtils_Test extends TestBase {
                // Test with ignoreWhitespaceAndComments=true - triggers code 
path
                assertTrue(isProbablyJsonObject("  {}  ", true)); // Valid, no 
characters after '}'
                assertTrue(isProbablyJsonObject("  /*comment*/ {key:value} 
/*comment*/  ", true)); // Valid, only comments/whitespace after '}'
-               // Test with newline to ensure the code path is covered 
+               // Test with newline to ensure the code path is covered
                // Code path: c == '\n' branch
                assertTrue(isProbablyJsonObject("  {key:value} //comment\n  ", 
true)); // Valid, // comment with newline
                // Code path: c == -1 branch (EOF)
@@ -4256,17 +4256,6 @@ class StringUtils_Test extends TestBase {
                assertTrue(notContains("test", new StringBuffer("xx")));
        }
 
-       
//====================================================================================================
-       // nullIfEmpty(String)
-       
//====================================================================================================
-       @Test
-       void a137_nullIfEmpty() {
-               assertNull(nullIfEmpty(null));
-               assertNull(nullIfEmpty(""));
-               assertNotNull(nullIfEmpty("x"));
-               assertEquals("test", nullIfEmpty("test"));
-       }
-
        
//====================================================================================================
        // obfuscate(String)
        
//====================================================================================================
@@ -6843,8 +6832,8 @@ class StringUtils_Test extends TestBase {
                assertFalse(result3b.contains("verylongword")); // Long word 
should be broken
                // Test word that breaks into multiple chunks (covers code path)
                // Word length 15, wrapLength 5 -> 3 chunks of 5, 5, 5
-               // This tests: wordPos > 0 , append chunk , advance position 
-               // And: remaining <= wrapLength , append remaining , break 
+               // This tests: wordPos > 0 , append chunk , advance position
+               // And: remaining <= wrapLength , append remaining , break
                var result3c = wrap("abcdefghijklmno here", 5, "\n");
                assertTrue(result3c.contains("abcde")); // First chunk (wordPos 
== 0, no newline before)
                assertTrue(result3c.contains("fghij")); // Second chunk 
(wordPos > 0, newline before, code path)
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/Utils_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/Utils_Test.java
index 8f6b3a3345..946b73b131 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/Utils_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/Utils_Test.java
@@ -1155,5 +1155,76 @@ class Utils_Test extends TestBase {
                assertEquals("test", unwrap("test"));
                assertEquals(123, unwrap(123));
        }
+
+       
//====================================================================================================
+       // nullIfEmpty(String)
+       
//====================================================================================================
+       @Test
+       void a059_nullIfEmpty_String() {
+               assertNull(nullIfEmpty((String)null));
+               assertNull(nullIfEmpty(""));
+               assertNotNull(nullIfEmpty("x"));
+               assertEquals("test", nullIfEmpty("test"));
+       }
+
+       
//====================================================================================================
+       // nullIfEmpty(Map)
+       
//====================================================================================================
+       @Test
+       void a060_nullIfEmpty_Map() {
+               // Null map
+               assertNull(nullIfEmpty((Map<String,Integer>)null));
+
+               // Empty map
+               Map<String,Integer> empty = new HashMap<>();
+               assertNull(nullIfEmpty(empty));
+
+               // Non-empty map
+               Map<String,Integer> nonEmpty = new HashMap<>();
+               nonEmpty.put("a", 1);
+               assertNotNull(nullIfEmpty(nonEmpty));
+               assertSame(nonEmpty, nullIfEmpty(nonEmpty));
+               assertEquals(1, nullIfEmpty(nonEmpty).size());
+       }
+
+       
//====================================================================================================
+       // nullIfEmpty(List)
+       
//====================================================================================================
+       @Test
+       void a061_nullIfEmpty_List() {
+               // Null list
+               assertNull(nullIfEmpty((List<String>)null));
+
+               // Empty list
+               List<String> empty = new ArrayList<>();
+               assertNull(nullIfEmpty(empty));
+
+               // Non-empty list
+               List<String> nonEmpty = new ArrayList<>();
+               nonEmpty.add("a");
+               assertNotNull(nullIfEmpty(nonEmpty));
+               assertSame(nonEmpty, nullIfEmpty(nonEmpty));
+               assertEquals(1, nullIfEmpty(nonEmpty).size());
+       }
+
+       
//====================================================================================================
+       // nullIfEmpty(Set)
+       
//====================================================================================================
+       @Test
+       void a062_nullIfEmpty_Set() {
+               // Null set
+               assertNull(nullIfEmpty((Set<String>)null));
+
+               // Empty set
+               Set<String> empty = new HashSet<>();
+               assertNull(nullIfEmpty(empty));
+
+               // Non-empty set
+               Set<String> nonEmpty = new HashSet<>();
+               nonEmpty.add("a");
+               assertNotNull(nullIfEmpty(nonEmpty));
+               assertSame(nonEmpty, nullIfEmpty(nonEmpty));
+               assertEquals(1, nullIfEmpty(nonEmpty).size());
+       }
 }
 

Reply via email to