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 4caf3f5877 juneau-marshall improvements
4caf3f5877 is described below

commit 4caf3f58777f21379fde0efc3186c98eeb05ebf9
Author: James Bognar <[email protected]>
AuthorDate: Thu Dec 18 13:26:46 2025 -0500

    juneau-marshall improvements
---
 AI.md                                              |   5 +
 .../juneau/bean/openapi3/SecurityRequirement.java  |   2 +-
 .../annotation/AppliedAnnotationObject.java        |  42 +--
 .../apache/juneau/commons/reflect/ClassInfo.java   |   9 +-
 .../apache/juneau/commons/settings/Settings.java   |   2 +-
 .../juneau/commons/utils/AssertionUtils.java       |  32 +-
 .../main/java/org/apache/juneau/config/Config.java |   2 +-
 .../java/org/apache/juneau/jena/RdfSerializer.java |   2 +-
 .../main/java/org/apache/juneau/BeanContext.java   | 370 +++++++++++--------
 .../java/org/apache/juneau/BeanContextable.java    |  18 +-
 .../src/main/java/org/apache/juneau/BeanMeta.java  |   4 +-
 .../java/org/apache/juneau/BeanPropertyMeta.java   |   3 +-
 .../java/org/apache/juneau/BeanPropertyValue.java  |   1 -
 .../apache/juneau/BeanProxyInvocationHandler.java  |  94 ++++-
 .../main/java/org/apache/juneau/BeanRegistry.java  |  26 +-
 .../main/java/org/apache/juneau/BeanSession.java   |  30 +-
 .../src/main/java/org/apache/juneau/ClassMeta.java |   8 +-
 .../src/main/java/org/apache/juneau/Context.java   |  12 +-
 .../java/org/apache/juneau/ContextSession.java     |   2 +-
 .../apache/juneau/httppart/BaseHttpPartParser.java |   2 +-
 .../juneau/jsonschema/JsonSchemaGenerator.java     |  14 +-
 .../main/java/org/apache/juneau/parser/Parser.java |  13 +-
 .../org/apache/juneau/serializer/Serializer.java   |   6 +-
 .../java/org/apache/juneau/xml/XmlSerializer.java  |  15 +-
 .../apache/juneau/xml/XmlSerializerSession.java    |   9 +-
 .../org/apache/juneau/rest/client/RestClient.java  |   8 +-
 .../org/apache/juneau/rest/client/RestRequest.java |   2 +-
 .../java/org/apache/juneau/rest/RestContext.java   |  36 +-
 .../java/org/apache/juneau/rest/RestOpContext.java |  42 +--
 .../java/org/apache/juneau/BeanContext_Test.java   | 109 ++++++
 .../org/apache/juneau/BeanPropertyValue_Test.java  | 105 ++++++
 .../juneau/BeanProxyInvocationHandler_Test.java    | 405 +++++++++++++++++++++
 .../annotation/BeanConfigAnnotation_Test.java      |   7 +-
 .../juneau/commons/collections/MultiSet_Test.java  |   3 +-
 .../juneau/commons/utils/AssertionUtils_Test.java  |  14 +-
 35 files changed, 1125 insertions(+), 329 deletions(-)

diff --git a/AI.md b/AI.md
index 33f4585ef1..af9c22b464 100644
--- a/AI.md
+++ b/AI.md
@@ -31,6 +31,11 @@ This document outlines the rules, guidelines, and best 
practices that AI assista
 
 ## Core Working Principles
 
+### 0. Change Evaluation
+- After each code modification, provide a brief (1-2 sentence) evaluation of 
the change
+- Explain what was changed and why it improves the codebase
+- This helps document the reasoning behind modifications and ensures changes 
are intentional
+
 ### 1. Code Quality and Consistency
 - Follow existing code patterns and conventions
 - Maintain consistency with the existing codebase
diff --git 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecurityRequirement.java
 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecurityRequirement.java
index 93c91ae776..2adc3fd0df 100644
--- 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecurityRequirement.java
+++ 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecurityRequirement.java
@@ -60,7 +60,7 @@ public class SecurityRequirement extends OpenApiElement {
         */
        public SecurityRequirement addRequirement(String schemeName, 
String...scopes) {
                assertArgNotNull("schemeName", schemeName);
-               assertVarargsNotNull("scopes", scopes);
+               assertArgNoNulls("scopes", scopes);
                if (requirements == null)
                        requirements = new LinkedHashMap<>();
                requirements.put(schemeName, l(scopes));
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/annotation/AppliedAnnotationObject.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/annotation/AppliedAnnotationObject.java
index 6e43ea6f3e..a90dc7924c 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/annotation/AppliedAnnotationObject.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/annotation/AppliedAnnotationObject.java
@@ -168,7 +168,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public Builder on(String...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        for (var v : values)
                                on = addAll(on, v);
                        return this;
@@ -214,7 +214,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderC on(Constructor<?>...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on(info(v).getFullName());
                        return this;
@@ -227,7 +227,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderC on(ConstructorInfo...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on(v.getFullName());
                        return this;
@@ -274,7 +274,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderM on(Method...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on(info(v).getFullName());
                        return this;
@@ -287,7 +287,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderM on(MethodInfo...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on(v.getFullName());
                        return this;
@@ -337,7 +337,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderMF on(Field...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on(info(v).getFullName());
                        return this;
@@ -350,7 +350,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderMF on(FieldInfo...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on(v.getFullName());
                        return this;
@@ -363,7 +363,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderMF on(Method...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on(info(v).getFullName());
                        return this;
@@ -376,7 +376,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderMF on(MethodInfo...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on(v.getFullName());
                        return this;
@@ -432,7 +432,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderT on(Class<?>...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on = addAll(on, v.getName());
                        return this;
@@ -445,7 +445,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderT on(ClassInfo...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on = addAll(on, cn(v));
                        return this;
@@ -459,7 +459,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 */
                @SuppressWarnings("unchecked")
                public BuilderT onClass(Class<?>...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                onClass = addAll(onClass, v);
                        return this;
@@ -473,7 +473,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 */
                @SuppressWarnings("unchecked")
                public BuilderT onClass(ClassInfo...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                onClass = addAll(onClass, v.inner());
                        return this;
@@ -514,7 +514,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderTM on(Method...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on(info(v).getFullName());
                        return this;
@@ -527,7 +527,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderTM on(MethodInfo...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on(v.getFullName());
                        return this;
@@ -582,7 +582,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderTMF on(Field...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on(info(v).getFullName());
                        return this;
@@ -595,7 +595,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderTMF on(FieldInfo...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on(v.getFullName());
                        return this;
@@ -608,7 +608,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderTMF on(Method...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on(info(v).getFullName());
                        return this;
@@ -621,7 +621,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderTMF on(MethodInfo...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on(v.getFullName());
                        return this;
@@ -665,7 +665,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderTMFC on(Constructor<?>...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on(info(v).getFullName());
                        return this;
@@ -678,7 +678,7 @@ public class AppliedAnnotationObject extends 
AnnotationObject {
                 * @return This object.
                 */
                public BuilderTMFC on(ConstructorInfo...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                on(v.getFullName());
                        return this;
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
index 062c8ed55e..411abc63ca 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
@@ -65,7 +65,7 @@ import org.apache.juneau.commons.collections.*;
  *
  */
 @SuppressWarnings({ "unchecked", "rawtypes" })
-public class ClassInfo extends ElementInfo implements Annotatable, Type {
+public class ClassInfo extends ElementInfo implements Annotatable, Type, 
Comparable<ClassInfo> {
 
        private static final Cache<Class,ClassInfoTyped> CACHE = 
Cache.of(Class.class, ClassInfoTyped.class).build();
 
@@ -495,6 +495,13 @@ public class ClassInfo extends ElementInfo implements 
Annotatable, Type {
                return (o instanceof ClassInfo o2) && eq(this, o2, (x, y) -> 
eq(x.innerType, y.innerType));
        }
 
+       @Override
+       public int compareTo(ClassInfo o) {
+               if (o == null)
+                       return 1;
+               return getName().compareTo(o.getName());
+       }
+
        /**
         * Returns all fields on this class and all parent classes.
         *
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/settings/Settings.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/settings/Settings.java
index 187645e70a..45876c2a19 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/settings/Settings.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/settings/Settings.java
@@ -224,7 +224,7 @@ public class Settings {
                 */
                @SafeVarargs
                public final Builder setSources(SettingSource...sources) {
-                       assertVarargsNotNull("sources", sources);
+                       assertArgNoNulls("sources", sources);
                        this.sources.clear();
                        for (var source : sources) {
                                this.sources.add(source);
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/AssertionUtils.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/AssertionUtils.java
index 514accf17f..7d853f9afc 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/AssertionUtils.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/AssertionUtils.java
@@ -16,6 +16,8 @@
  */
 package org.apache.juneau.commons.utils;
 
+import java.util.Collection;
+
 import static org.apache.juneau.commons.utils.ThrowableUtils.*;
 import static org.apache.juneau.commons.utils.Utils.*;
 
@@ -349,11 +351,39 @@ public class AssertionUtils {
         * @return The same object.
         * @throws IllegalArgumentException Thrown if the specified varargs 
array or any of its elements are <jk>null</jk>.
         */
-       public static final <T> T[] assertVarargsNotNull(String name, T[] o) 
throws IllegalArgumentException {
+       public static final <T> T[] assertArgNoNulls(String name, T[] o) throws 
IllegalArgumentException {
                assertArgNotNull(name, o);
                for (var i = 0; i < o.length; i++)
                        assertArg(nn(o[i]), "Argument ''{0}'' parameter {1} 
cannot be null.", name, i);
                return o;
        }
 
+       /**
+        * Throws an {@link IllegalArgumentException} if the specified 
collection or any of its elements are <jk>null</jk>.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      <jk>import static</jk> 
org.apache.juneau.commons.utils.AssertionUtils.*;
+        *
+        *      <jk>public</jk> <jk>void</jk> setValues(List&lt;String&gt; 
<jv>values</jv>) {
+        *              
<jsm>assertCollectionArgNotNull</jsm>(<js>"values"</js>, <jv>values</jv>);
+        *              ...
+        *      }
+        * </p>
+        *
+        * @param <T> The element type.
+        * @param <C> The collection type.
+        * @param name The argument name.
+        * @param collection The collection to check.
+        * @return The same collection.
+        * @throws IllegalArgumentException Thrown if the specified collection 
or any of its elements are <jk>null</jk>.
+        */
+       public static final <T, C extends Collection<T>> C 
assertArgNoNulls(String name, C collection) throws IllegalArgumentException {
+               assertArgNotNull(name, collection);
+               var i = 0;
+               for (var element : collection)
+                       assertArg(nn(element), "Argument ''{0}'' element at 
index {1} cannot be null.", name, i++);
+               return collection;
+       }
+
 }
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 c01668f259..695850d4b3 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
@@ -266,7 +266,7 @@ public class Config extends Context implements 
ConfigEventListener {
                 * @return This object.
                 */
                public Builder mods(Mod...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        for (var value : values)
                                mods.put(value.getId(), value);
                        return this;
diff --git 
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
 
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
index 9b33a74512..2ef5a9a577 100644
--- 
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
+++ 
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
@@ -1182,7 +1182,7 @@ public class RdfSerializer extends WriterSerializer 
implements RdfMetaProvider {
                 * @return This object.
                 */
                public Builder namespaces(Namespace...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        namespaces = addAll(namespaces, values);
                        return this;
                }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
index 703c5837d7..9c604844d4 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
@@ -23,7 +23,6 @@ import static org.apache.juneau.commons.utils.ClassUtils.*;
 import static org.apache.juneau.commons.utils.CollectionUtils.*;
 import static org.apache.juneau.commons.utils.ThrowableUtils.*;
 import static org.apache.juneau.commons.utils.Utils.*;
-import static java.util.Comparator.*;
 
 import java.beans.*;
 import java.io.*;
@@ -175,18 +174,6 @@ public class BeanContext extends Context {
 
                private static final Cache<HashKey,BeanContext> CACHE = 
Cache.of(HashKey.class, BeanContext.class).build();
 
-               private static Set<Class<?>> classSet() {
-                       return new TreeSet<>(comparing(Class::getName));
-               }
-
-               private static Set<Class<?>> toClassSet(Collection<Class<?>> 
copy) {
-                       if (copy == null)
-                               return null;
-                       var x = classSet();
-                       x.addAll(copy);
-                       return x;
-               }
-
                private Visibility beanClassVisibility;
                private Visibility beanConstructorVisibility;
                private Visibility beanMethodVisibility;
@@ -213,9 +200,9 @@ public class BeanContext extends Context {
                private Locale locale;
                private TimeZone timeZone;
                private Class<? extends PropertyNamer> propertyNamer;
-               private List<Class<?>> beanDictionary;
+               private List<ClassInfo> beanDictionary;
                private List<Object> swaps;
-               private Set<Class<?>> notBeanClasses;
+               private Set<ClassInfo> notBeanClasses;
                private Set<String> notBeanPackages;
 
                /**
@@ -245,7 +232,7 @@ public class BeanContext extends Context {
                        ignoreUnknownEnumValues = 
env("BeanContext.ignoreUnknownEnumValues", false);
                        locale = env("BeanContext.locale").map(x -> 
Locale.forLanguageTag(x)).orElse(Locale.getDefault());
                        mediaType = env("BeanContext.mediaType").map(x -> 
MediaType.of(x)).orElse(null);
-                       notBeanClasses = classSet();
+                       notBeanClasses = new TreeSet<>();
                        notBeanPackages = new TreeSet<>();
                        propertyNamer = null;
                        sortProperties = env("BeanContext.sortProperties", 
false);
@@ -284,7 +271,7 @@ public class BeanContext extends Context {
                        ignoreUnknownEnumValues = 
copyFrom.ignoreUnknownEnumValues;
                        locale = copyFrom.locale;
                        mediaType = copyFrom.mediaType;
-                       notBeanClasses = toClassSet(copyFrom.notBeanClasses);
+                       notBeanClasses = new TreeSet<>(copyFrom.notBeanClasses);
                        notBeanPackages = toSortedSet(copyFrom.notBeanPackages, 
false);
                        propertyNamer = copyFrom.propertyNamer;
                        sortProperties = copyFrom.sortProperties;
@@ -323,7 +310,7 @@ public class BeanContext extends Context {
                        ignoreUnknownEnumValues = 
copyFrom.ignoreUnknownEnumValues;
                        locale = copyFrom.locale;
                        mediaType = copyFrom.mediaType;
-                       notBeanClasses = toClassSet(copyFrom.notBeanClasses);
+                       notBeanClasses = new TreeSet<>(copyFrom.notBeanClasses);
                        notBeanPackages = toSortedSet(copyFrom.notBeanPackages);
                        propertyNamer = copyFrom.propertyNamer;
                        sortProperties = copyFrom.sortProperties;
@@ -462,7 +449,7 @@ public class BeanContext extends Context {
                 * @return The bean dictionary list.
                 * @see #beanDictionary(Class...)
                 */
-               public List<Class<?>> beanDictionary() {
+               public List<ClassInfo> beanDictionary() {
                        return beanDictionary;
                }
 
@@ -549,7 +536,7 @@ public class BeanContext extends Context {
                 *      <li class='ja'>{@link 
org.apache.juneau.annotation.Beanp#dictionary()}
                 *      <li class='ja'>{@link 
org.apache.juneau.annotation.BeanConfig#dictionary()}
                 *      <li class='ja'>{@link 
org.apache.juneau.annotation.BeanConfig#dictionary_replace()}
-                *      <li class='jm'>{@link 
org.apache.juneau.BeanContext.Builder#beanDictionary(Class...)}
+                *      <li class='jm'>{@link 
org.apache.juneau.BeanContext.Builder#beanDictionary(ClassInfo...)}
                 * </ul>
                 *
                 * @param values
@@ -557,26 +544,40 @@ public class BeanContext extends Context {
                 *      <br>Cannot contain <jk>null</jk> values.
                 * @return This object.
                 */
-               public Builder beanDictionary(Class<?>...values) {
-                       assertVarargsNotNull("values", values);
+               public Builder beanDictionary(ClassInfo...values) {
+                       assertArgNoNulls("values", values);
                        return beanDictionary(l(values));
                }
 
                /**
-                * Same as {@link #beanDictionary(Class...)} but allows you to 
pass in a collection of classes.
+                * Same as {@link #beanDictionary(ClassInfo...)} but allows you 
to pass in a collection of class info objects.
                 *
                 * @param values
                 *      The values to add to this setting.
-                *      <br>Cannot be <jk>null</jk>.
+                *      <br>Cannot be <jk>null</jk> or contain <jk>null</jk> 
values.
                 * @return This object.
-                * @see #beanDictionary(Class...)
+                * @see #beanDictionary(ClassInfo...)
                 */
-               public Builder beanDictionary(Collection<Class<?>> values) {
-                       assertArgNotNull("values", values);
+               public Builder beanDictionary(Collection<ClassInfo> values) {
+                       assertArgNoNulls("values", values);
                        beanDictionary().addAll(0, values);
                        return this;
                }
 
+               /**
+                * Convenience method for {@link #beanDictionary(ClassInfo...)} 
that accepts {@link Class} objects.
+                *
+                * @param values
+                *      The values to add to this setting.
+                *      <br>Cannot contain <jk>null</jk> values.
+                * @return This object.
+                * @see #beanDictionary(ClassInfo...)
+                */
+               public Builder beanDictionary(Class<?>...values) {
+                       assertArgNoNulls("values", values);
+                       return 
beanDictionary(Stream.of(values).map(ReflectionUtils::info).toArray(ClassInfo[]::new));
+               }
+
                /**
                 * Minimum bean field visibility.
                 *
@@ -1733,7 +1734,7 @@ public class BeanContext extends Context {
                 */
                public Builder dictionaryOn(Class<?> on, Class<?>...values) {
                        assertArgNotNull("on", on);
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        return 
annotations(BeanAnnotation.create(on).dictionary(values).build());
                }
 
@@ -2549,7 +2550,7 @@ public class BeanContext extends Context {
                 * @return This object.
                 */
                public Builder interfaces(Class<?>...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        for (var v : value)
                                
annotations(BeanAnnotation.create(v).interfaceClass(v).build());
                        return this;
@@ -2642,15 +2643,15 @@ public class BeanContext extends Context {
                }
 
                /**
-                * Returns the list of not-bean classes.
+                * Returns the set of not-bean classes.
                 *
                 * <p>
-                * Gives access to the inner list if you need to make more than 
simple additions via {@link #notBeanClasses(Class...)}.
+                * Gives access to the inner set if you need to make more than 
simple additions via {@link #notBeanClasses(ClassInfo...)}.
                 *
-                * @return The list of not-bean classes.
-                * @see #notBeanClasses(Class...)
+                * @return The set of not-bean classes.
+                * @see #notBeanClasses(ClassInfo...)
                 */
-               public Set<Class<?>> notBeanClasses() {
+               public Set<ClassInfo> notBeanClasses() {
                        return notBeanClasses;
                }
 
@@ -2700,31 +2701,44 @@ public class BeanContext extends Context {
                 *
                 * @param values
                 *      The values to add to this setting.
-                *      <br>Values can consist of any of the following types:
-                *      <ul>
-                *              <li>Classes.
-                *              <li>Arrays and collections of classes.
-                *      </ul>
+                *      <br>Cannot contain <jk>null</jk> values.
                 * @return This object.
                 */
-               public Builder notBeanClasses(Class<?>...values) {
-                       return notBeanClasses(l(values));
+               public Builder notBeanClasses(ClassInfo...values) {
+                       assertArgNoNulls("values", values);
+                       notBeanClasses().addAll(l(values));
+                       return this;
                }
 
                /**
-                * Same as {@link #notBeanClasses(Class...)} but allows you to 
pass in a collection of classes.
+                * Same as {@link #notBeanClasses(ClassInfo...)} but allows you 
to pass in a collection of class info objects.
                 *
                 * @param values
                 *      The values to add to this setting.
+                *      <br>Cannot be <jk>null</jk> or contain <jk>null</jk> 
values.
                 * @return This object.
-                * @see #notBeanClasses(Class...)
+                * @see #notBeanClasses(ClassInfo...)
                 */
-               public Builder notBeanClasses(Collection<Class<?>> values) {
-                       assertArgNotNull("values", values);
+               public Builder notBeanClasses(Collection<ClassInfo> values) {
+                       assertArgNoNulls("values", values);
                        notBeanClasses().addAll(values);
                        return this;
                }
 
+               /**
+                * Convenience method for {@link #notBeanClasses(ClassInfo...)} 
that accepts {@link Class} objects.
+                *
+                * @param values
+                *      The values to add to this setting.
+                *      <br>Cannot contain <jk>null</jk> values.
+                * @return This object.
+                * @see #notBeanClasses(ClassInfo...)
+                */
+               public Builder notBeanClasses(Class<?>...values) {
+                       assertArgNoNulls("values", values);
+                       return 
notBeanClasses(Stream.of(values).map(ReflectionUtils::info).toArray(ClassInfo[]::new));
+               }
+
                /**
                 * Returns the list of not-bean Java package names.
                 *
@@ -2743,12 +2757,12 @@ public class BeanContext extends Context {
                 *
                 * @param values
                 *      The values to add to this setting.
-                *      <br>Cannot be <jk>null</jk>.
+                *      <br>Cannot be <jk>null</jk> or contain <jk>null</jk> 
values.
                 * @return This object.
                 * @see #notBeanPackages(String...)
                 */
                public Builder notBeanPackages(Collection<String> values) {
-                       assertArgNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        notBeanPackages().addAll(values);
                        return this;
                }
@@ -2791,7 +2805,7 @@ public class BeanContext extends Context {
                 * @return This object.
                 */
                public Builder notBeanPackages(String...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        return notBeanPackages(l(values));
                }
 
@@ -2970,7 +2984,7 @@ public class BeanContext extends Context {
                 * @return This object.
                 */
                public Builder sortProperties(Class<?>...on) {
-                       assertVarargsNotNull("on", on);
+                       assertArgNoNulls("on", on);
                        for (var c : on)
                                
annotations(BeanAnnotation.create(c).sort(true).build());
                        return this;
@@ -3110,7 +3124,7 @@ public class BeanContext extends Context {
                 * @return This object.
                 */
                public Builder swaps(Class<?>...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        swaps().addAll(0, accumulate(values));
                        return this;
                }
@@ -3198,7 +3212,7 @@ public class BeanContext extends Context {
                 * @return This object.
                 */
                public Builder swaps(Object...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        swaps().addAll(0, accumulate(values));
                        return this;
                }
@@ -3503,7 +3517,7 @@ public class BeanContext extends Context {
         * Any beans in packages in this list will not be considered beans.
         */
        // @formatter:off
-       private static final String[] DEFAULT_NOTBEAN_PACKAGES = {
+       private static final List<String> DEFAULT_NOTBEAN_PACKAGES = l(
                "java.lang",
                "java.lang.annotation",
                "java.lang.ref",
@@ -3512,7 +3526,7 @@ public class BeanContext extends Context {
                "java.net",
                "java.nio.*",
                "java.util.*"
-       };
+       );
        // @formatter:on
 
        /*
@@ -3520,15 +3534,15 @@ public class BeanContext extends Context {
         * Anything in this list will not be considered beans.
         */
        // @formatter:off
-       private static final Class<?>[] DEFAULT_NOTBEAN_CLASSES = {
-               Map.class,
-               Collection.class,
-               Reader.class,
-               Writer.class,
-               InputStream.class,
-               OutputStream.class,
-               Throwable.class
-       };
+       private static final List<ClassInfo> DEFAULT_NOTBEAN_CLASSES = l(
+               info(Map.class),
+               info(Collection.class),
+               info(Reader.class),
+               info(Writer.class),
+               info(InputStream.class),
+               info(OutputStream.class),
+               info(Throwable.class)
+       );
        // @formatter:on
 
        /** Default config.  All default settings. */
@@ -3549,49 +3563,48 @@ public class BeanContext extends Context {
                return new Builder();
        }
 
-       protected final boolean beanMapPutReturnsOldValue;
-       protected final boolean beansRequireDefaultConstructor;
-       protected final boolean beansRequireSerializable;
-       protected final boolean beansRequireSettersForGetters;
-       protected final boolean beansRequireSomeProperties;
-       protected final boolean findFluentSetters;
-       protected final boolean ignoreInvocationExceptionsOnGetters;
-       protected final boolean ignoreInvocationExceptionsOnSetters;
-       protected final boolean ignoreMissingSetters;
-       protected final boolean ignoreTransientFields;
-       protected final boolean ignoreUnknownBeanProperties;
-       protected final boolean ignoreUnknownEnumValues;
-       protected final boolean ignoreUnknownNullBeanProperties;
-       protected final boolean sortProperties;
-       protected final boolean useEnumNames;
-       protected final boolean useInterfaceProxies;
-       protected final boolean useJavaBeanIntrospector;
-       protected final Class<? extends PropertyNamer> propertyNamer;
-       protected final Class<?>[] notBeanClassesArray;
-       protected final ClassMeta<Class> cmClass;  // Reusable ClassMeta that 
represents general Classes.
-       protected final ClassMeta<Object> cmObject;  // Reusable ClassMeta that 
represents general Objects.
-       protected final ClassMeta<String> cmString;  // Reusable ClassMeta that 
represents general Strings.
-       protected final HashKey hashKey;
-       protected final List<Class<?>> beanDictionary;
-       protected final List<Class<?>> notBeanClasses;
-       protected final List<Object> swaps;
-       protected final List<String> notBeanPackages;
-       protected final Locale locale;
-       protected final Map<Class,ClassMeta> cmCache;
-       protected final MediaType mediaType;
-       protected final ObjectSwap[] swapArray;
-       protected final String typePropertyName;
-       protected final String[] notBeanPackageNames;
-       protected final String[] notBeanPackagePrefixes;
-       protected final TimeZone timeZone;
-       protected final Visibility beanClassVisibility;
-       protected final Visibility beanConstructorVisibility;
-       protected final Visibility beanFieldVisibility;
-       protected final Visibility beanMethodVisibility;
+       private final AtomicReference<WriterSerializer> beanToStringSerializer 
= new AtomicReference<>();
        private final BeanRegistry beanRegistry;
        private final BeanSession defaultSession;
+       private final boolean beanMapPutReturnsOldValue;
+       private final boolean beansRequireDefaultConstructor;
+       private final boolean beansRequireSerializable;
+       private final boolean beansRequireSettersForGetters;
+       private final boolean beansRequireSomeProperties;
+       private final boolean findFluentSetters;
+       private final boolean ignoreInvocationExceptionsOnGetters;
+       private final boolean ignoreInvocationExceptionsOnSetters;
+       private final boolean ignoreMissingSetters;
+       private final boolean ignoreTransientFields;
+       private final boolean ignoreUnknownBeanProperties;
+       private final boolean ignoreUnknownEnumValues;
+       private final boolean ignoreUnknownNullBeanProperties;
+       private final boolean sortProperties;
+       private final boolean useEnumNames;
+       private final boolean useInterfaceProxies;
+       private final boolean useJavaBeanIntrospector;
+       private final Class<? extends PropertyNamer> propertyNamer;
+       private final ClassMeta<Class> cmClass;  // Reusable ClassMeta that 
represents general Classes.
+       private final ClassMeta<Object> cmObject;  // Reusable ClassMeta that 
represents general Objects.
+       private final ClassMeta<String> cmString;  // Reusable ClassMeta that 
represents general Strings.
+       private final HashKey hashKey;
+       private final List<ClassInfo> beanDictionary;
+       private final List<ClassInfo> notBeanClasses;
+       private final List<Object> swaps;
+       private final List<String> notBeanPackages;
+       private final Locale locale;
+       private final Map<Class,ClassMeta> cmCache;
+       private final MediaType mediaType;
+       private final List<ObjectSwap<?,?>> objectSwaps;
        private final PropertyNamer propertyNamerBean;
-       private final AtomicReference<WriterSerializer> beanToStringSerializer 
= new AtomicReference<>();
+       private final String typePropertyName;
+       private final Set<String> notBeanPackageNames;
+       private final List<String> notBeanPackagePrefixes;
+       private final TimeZone timeZone;
+       private final Visibility beanClassVisibility;
+       private final Visibility beanConstructorVisibility;
+       private final Visibility beanFieldVisibility;
+       private final Visibility beanMethodVisibility;
 
        /**
         * Constructor.
@@ -3603,7 +3616,7 @@ public class BeanContext extends Context {
 
                beanClassVisibility = builder.beanClassVisibility;
                beanConstructorVisibility = builder.beanConstructorVisibility;
-               beanDictionary = 
opt(builder.beanDictionary).map(Collections::unmodifiableList).orElse(l());
+               beanDictionary = u(copyOf(builder.beanDictionary));
                beanFieldVisibility = builder.beanFieldVisibility;
                beanMapPutReturnsOldValue = builder.beanMapPutReturnsOldValue;
                beanMethodVisibility = builder.beanMethodVisibility;
@@ -3622,22 +3635,23 @@ public class BeanContext extends Context {
                ignoreUnknownNullBeanProperties = ! 
builder.disableIgnoreUnknownNullBeanProperties;
                locale = nn(builder.locale) ? builder.locale : 
Locale.getDefault();
                mediaType = builder.mediaType;
-               notBeanClasses = 
opt(builder.notBeanClasses).map(ArrayList::new).map(Collections::unmodifiableList).orElse(l());
-               notBeanPackages = 
opt(builder.notBeanPackages).map(ArrayList::new).map(Collections::unmodifiableList).orElse(l());
+               notBeanPackages = u(new ArrayList<>(builder.notBeanPackages));
                propertyNamer = nn(builder.propertyNamer) ? 
builder.propertyNamer : BasicPropertyNamer.class;
                sortProperties = builder.sortProperties;
-               swaps = 
opt(builder.swaps).map(Collections::unmodifiableList).orElse(l());
+               swaps = u(copyOf(builder.swaps));
                timeZone = builder.timeZone;
                typePropertyName = nn(builder.typePropertyName) ? 
builder.typePropertyName : "_type";
                useEnumNames = builder.useEnumNames;
                useInterfaceProxies = ! builder.disableInterfaceProxies;
                useJavaBeanIntrospector = builder.useJavaBeanIntrospector;
 
-               notBeanClassesArray = notBeanClasses.isEmpty() ? 
DEFAULT_NOTBEAN_CLASSES : Stream.of(notBeanClasses, 
l(DEFAULT_NOTBEAN_CLASSES)).flatMap(Collection::stream).toArray(Class[]::new);
+               var builderNotBeanClasses = new 
ArrayList<>(builder.notBeanClasses);
+               notBeanClasses = builderNotBeanClasses.isEmpty() ? 
DEFAULT_NOTBEAN_CLASSES : Stream.concat(builderNotBeanClasses.stream(), 
DEFAULT_NOTBEAN_CLASSES.stream()).distinct().toList();
 
-               String[] _notBeanPackages = notBeanPackages.isEmpty() ? 
DEFAULT_NOTBEAN_PACKAGES : Stream.of(notBeanPackages, 
l(DEFAULT_NOTBEAN_PACKAGES)).flatMap(Collection::stream).toArray(String[]::new);
-               notBeanPackageNames = Stream.of(_notBeanPackages).filter(x -> ! 
x.endsWith(".*")).toArray(String[]::new);
-               notBeanPackagePrefixes = Stream.of(_notBeanPackages).filter(x 
-> x.endsWith(".*")).map(x -> x.substring(0, x.length() - 
2)).toArray(String[]::new);
+               List<String> _notBeanPackages = notBeanPackages.isEmpty() ? 
DEFAULT_NOTBEAN_PACKAGES : Stream.concat(notBeanPackages.stream(), 
DEFAULT_NOTBEAN_PACKAGES.stream()).toList();
+               LinkedHashSet<String> _notBeanPackageNames = 
_notBeanPackages.stream().filter(x -> ! 
x.endsWith(".*")).collect(Collectors.toCollection(LinkedHashSet::new));
+               notBeanPackageNames = u(_notBeanPackageNames);
+               notBeanPackagePrefixes = _notBeanPackages.stream().filter(x -> 
x.endsWith(".*")).map(x -> x.substring(0, x.length() - 2)).toList();
 
                try {
                        propertyNamerBean = 
propertyNamer.getDeclaredConstructor().newInstance();
@@ -3645,21 +3659,21 @@ public class BeanContext extends Context {
                        throw toRex(e);
                }
 
-               LinkedList<ObjectSwap<?,?>> _swaps = new LinkedList<>();
+               var _objectSwaps = new LinkedList<ObjectSwap<?,?>>();
                swaps.forEach(x -> {
                        if (x instanceof ObjectSwap<?,?> os) {
-                               _swaps.add(os);
+                               _objectSwaps.add(os);
                        } else {
                                var ci = info((Class<?>)x);
                                if (ci.isChildOf(ObjectSwap.class))
-                                       
_swaps.add(BeanCreator.of(ObjectSwap.class).type(ci).run());
+                                       
_objectSwaps.add(BeanCreator.of(ObjectSwap.class).type(ci).run());
                                else if (ci.isChildOf(Surrogate.class))
-                                       
_swaps.addAll(SurrogateSwap.findObjectSwaps(ci.inner(), this));
+                                       
_objectSwaps.addAll(SurrogateSwap.findObjectSwaps(ci.inner(), this));
                                else
                                        throw rex("Invalid class {0} specified 
in BeanContext.swaps property.  Must be a subclass of ObjectSwap or 
Surrogate.", cn(ci.inner()));
                        }
                });
-               swapArray = _swaps.toArray(new ObjectSwap[_swaps.size()]);
+               objectSwaps = u(_objectSwaps);
 
                cmCache = new ConcurrentHashMap<>();
                cmCache.put(String.class, new ClassMeta(String.class, this));
@@ -3668,7 +3682,7 @@ public class BeanContext extends Context {
                cmObject = cmCache.get(Object.class);
                cmClass = cmCache.get(Class.class);
 
-               beanRegistry = new BeanRegistry(this, null);
+               beanRegistry = new BeanRegistry(this, null, list());
                defaultSession = createSession().unmodifiable().build();
        }
 
@@ -3762,8 +3776,10 @@ public class BeanContext extends Context {
         * @see BeanContext.Builder#beanDictionary()
         * @return
         *      The list of classes that make up the bean dictionary in this 
bean context.
+        *      <br>Never <jk>null</jk>.
+        *      <br>List is unmodifiable.
         */
-       public final List<Class<?>> getBeanDictionary() { return 
beanDictionary; }
+       public final List<ClassInfo> getBeanDictionary() { return 
beanDictionary; }
 
        /**
         * Minimum bean field visibility.
@@ -3780,13 +3796,13 @@ public class BeanContext extends Context {
         *
         * @param <T> The class type to get the meta-data on.
         * @param c The class to get the meta-data on.
+        *      <br>Cannot be <jk>null</jk>.
         * @return
         *      The {@link BeanMeta} for the specified class, or <jk>null</jk> 
if the class is not a bean per the settings on
         *      this context.
         */
        public final <T> BeanMeta<T> getBeanMeta(Class<T> c) {
-               if (c == null)
-                       return null;
+               assertArgNotNull("c", c);
                return getClassMeta(c).getBeanMeta();
        }
 
@@ -3876,11 +3892,11 @@ public class BeanContext extends Context {
         *
         * @param <T> The class of the object being passed in.
         * @param o The class to find the class type for.
-        * @return The ClassMeta object, or <jk>null</jk> if {@code o} is 
<jk>null</jk>.
+        *      <br>Cannot be <jk>null</jk>.
+        * @return The ClassMeta object.
         */
        public final <T> ClassMeta<T> getClassMetaForObject(T o) {
-               if (o == null)
-                       return null;
+               assertArgNotNull("o", o);
                return (ClassMeta<T>)getClassMeta(o.getClass());
        }
 
@@ -3902,6 +3918,41 @@ public class BeanContext extends Context {
         */
        public final MediaType getDefaultMediaType() { return mediaType; }
 
+       /**
+        * Hash key.
+        *
+        * @return The hash key.
+        */
+       protected final HashKey getHashKey() { return hashKey; }
+
+       /**
+        * Class metadata cache.
+        *
+        * @return The class metadata cache.
+        */
+       protected final Map<Class,ClassMeta> getCmCache() { return cmCache; }
+
+       /**
+        * Locale.
+        *
+        * @return The locale.
+        */
+       protected final Locale getLocale() { return locale; }
+
+       /**
+        * Media type.
+        *
+        * @return The media type.
+        */
+       protected final MediaType getMediaType() { return mediaType; }
+
+       /**
+        * Time zone.
+        *
+        * @return The time zone.
+        */
+       protected final TimeZone getTimeZone() { return timeZone; }
+
        /**
         * Time zone.
         *
@@ -3916,9 +3967,12 @@ public class BeanContext extends Context {
         *
         * @see BeanContext.Builder#notBeanPackages(String...)
         * @return
-        *      The list of fully-qualified package names to exclude from being 
classified as beans.
+        *      The set of fully-qualified package names to exclude from being 
classified as beans.
+        *      <br>Never <jk>null</jk>.
+        *      <br>Set is unmodifiable.
+        *      <br>Backed by a {@link LinkedHashSet} to preserve insertion 
order.
         */
-       public final String[] getNotBeanPackagesNames() { return 
notBeanPackageNames; }
+       public final Set<String> getNotBeanPackagesNames() { return 
notBeanPackageNames; }
 
        /**
         * Bean property namer.
@@ -3938,8 +3992,10 @@ public class BeanContext extends Context {
         * @see BeanContext.Builder#swaps(Class...)
         * @return
         *      The list POJO swaps defined.
+        *      <br>Never <jk>null</jk>.
+        *      <br>List is unmodifiable.
         */
-       public final ObjectSwap<?,?>[] getSwaps() { return swapArray; }
+       public final List<ObjectSwap<?,?>> getSwaps() { return objectSwaps; }
 
        /**
         * Returns <jk>true</jk> if the specified bean context shares the same 
cache as this bean context.
@@ -3948,22 +4004,12 @@ public class BeanContext extends Context {
         * Useful for testing purposes.
         *
         * @param bc The bean context to compare to.
+        *      <br>Cannot be <jk>null</jk>.
         * @return <jk>true</jk> if the bean contexts have equivalent settings 
and thus share caches.
         */
        public final boolean hasSameCache(BeanContext bc) {
-               return bc.cmCache == this.cmCache;
-       }
-
-       /**
-        * Returns <jk>true</jk> if the specified object is a bean.
-        *
-        * @param o The object to test.
-        * @return <jk>true</jk> if the specified object is a bean.  
<jk>false</jk> if the bean is <jk>null</jk>.
-        */
-       public boolean isBean(Object o) {
-               if (o == null)
-                       return false;
-               return getClassMetaForObject(o).isBean();
+               assertArgNotNull("bc", bc);
+               return bc.getCmCache() == this.getCmCache();
        }
 
        /**
@@ -4135,10 +4181,12 @@ public class BeanContext extends Context {
         *
         * @param <T> The class of the object being wrapped.
         * @param c The name of the class to create a new instance of.
+        *      <br>Cannot be <jk>null</jk>.
         * @return A new instance of the class.
         * @see BeanSession#newBeanMap(Class)
         */
        public <T> BeanMap<T> newBeanMap(Class<T> c) {
+               assertArgNotNull("c", c);
                return defaultSession.newBeanMap(c);
        }
 
@@ -4155,11 +4203,13 @@ public class BeanContext extends Context {
         * </p>
         *
         * @param <T> The class of the object being wrapped.
-        * @param object The object to wrap in a map interface.  Must not be 
null.
+        * @param object The object to wrap in a map interface.
+        *      <br>Cannot be <jk>null</jk>.
         * @return The wrapped object.
         * @see BeanSession#toBeanMap(Object)
         */
        public <T> BeanMap<T> toBeanMap(T object) {
+               assertArgNotNull("object", object);
                return defaultSession.toBeanMap(object);
        }
 
@@ -4168,7 +4218,7 @@ public class BeanContext extends Context {
         * Resolves the 'genericized' class meta at the specified position in 
the ClassMeta array.
         */
        private ClassMeta<?> getTypedClassMeta(ClassMeta<?>[] c, int pos) {
-               ClassMeta<?> cm = c[pos++];
+               var cm = c[pos++];
                if (cm.isCollection() || cm.isOptional()) {
                        var ce = c.length == pos ? object() : 
getTypedClassMeta(c, pos);
                        return (ce.isObject() ? cm : new ClassMeta(cm, null, 
null, ce));
@@ -4183,7 +4233,7 @@ public class BeanContext extends Context {
        private ClassMeta<?> resolveType(Type...t) {
                for (var tt : t) {
                        if (nn(tt)) {
-                               ClassMeta<?> cm = getClassMeta(tt);
+                               var cm = getClassMeta(tt);
                                if (tt != cmObject)
                                        return cm;
                        }
@@ -4221,7 +4271,7 @@ public class BeanContext extends Context {
         * @return The serializer.  May be <jk>null</jk> if all initialization 
has occurred.
         */
        protected WriterSerializer getBeanToStringSerializer() {
-               WriterSerializer result = beanToStringSerializer.get();
+               var result = beanToStringSerializer.get();
                if (result == null) {
                        if (JsonSerializer.DEFAULT == null)
                                return null;
@@ -4236,11 +4286,13 @@ public class BeanContext extends Context {
        /**
         * Bean class exclusions.
         *
-        * @see BeanContext.Builder#notBeanClasses(Class...)
+        * @see BeanContext.Builder#notBeanClasses(ClassInfo...)
         * @return
         *      The list of classes that are explicitly not beans.
+        *      <br>Never <jk>null</jk>.
+        *      <br>List is unmodifiable.
         */
-       protected final Class<?>[] getNotBeanClasses() { return 
notBeanClassesArray; }
+       protected final List<ClassInfo> getNotBeanClasses() { return 
notBeanClasses; }
 
        /**
         * Bean package exclusions.
@@ -4248,8 +4300,10 @@ public class BeanContext extends Context {
         * @see BeanContext.Builder#notBeanPackages(String...)
         * @return
         *      The list of package name prefixes to exclude from being 
classified as beans.
+        *      <br>Never <jk>null</jk>.
+        *      <br>List is unmodifiable.
         */
-       protected final String[] getNotBeanPackagesPrefixes() { return 
notBeanPackagePrefixes; }
+       protected final List<String> getNotBeanPackagesPrefixes() { return 
notBeanPackagePrefixes; }
 
        /**
         * Ignore transient fields.
@@ -4280,7 +4334,7 @@ public class BeanContext extends Context {
                                if (pn.startsWith(p2))
                                        return true;
                }
-               for (var exclude : notBeanClassesArray)
+               for (var exclude : notBeanClasses)
                        if (ci.isChildOf(exclude))
                                return true;
                return false;
@@ -4343,8 +4397,8 @@ public class BeanContext extends Context {
         * @return The new {@code ClassMeta} object wrapped around the type.
         */
        protected final <T> ClassMeta<T> resolveClassMeta(AnnotationInfo<Beanp> 
p, ClassInfo ci, TypeVariables typeVarImpls) {
-               ClassMeta<T> cm = resolveClassMeta(ci, typeVarImpls);
-               ClassMeta<T> cm2 = cm;
+               var cm = resolveClassMeta(ci, typeVarImpls);
+               var cm2 = cm;
 
                if (nn(p)) {
                        var beanp = p.inner();
@@ -4353,21 +4407,21 @@ public class BeanContext extends Context {
                                cm2 = resolveClassMeta(beanp.type(), 
typeVarImpls);
 
                        if (cm2.isMap()) {
-                               Class<?>[] pParams = (beanp.params().length == 
0 ? a(Object.class, Object.class) : beanp.params());
+                               var pParams = (beanp.params().length == 0 ? 
a(Object.class, Object.class) : beanp.params());
                                if (pParams.length != 2)
                                        throw rex("Invalid number of parameters 
specified for Map (must be 2): {0}", pParams.length);
-                               ClassMeta<?> keyType = resolveType(pParams[0], 
cm2.getKeyType(), cm.getKeyType());
-                               ClassMeta<?> valueType = 
resolveType(pParams[1], cm2.getValueType(), cm.getValueType());
+                               var keyType = resolveType(pParams[0], 
cm2.getKeyType(), cm.getKeyType());
+                               var valueType = resolveType(pParams[1], 
cm2.getValueType(), cm.getValueType());
                                if (keyType.isObject() && valueType.isObject())
                                        return cm2;
                                return new ClassMeta<>(cm2, keyType, valueType, 
null);
                        }
 
                        if (cm2.isCollection() || cm2.isOptional()) {
-                               Class<?>[] pParams = (beanp.params().length == 
0 ? a(Object.class) : beanp.params());
+                               var pParams = (beanp.params().length == 0 ? 
a(Object.class) : beanp.params());
                                if (pParams.length != 1)
                                        throw rex("Invalid number of parameters 
specified for {1} (must be 1): {0}", pParams.length, (cm2.isCollection() ? 
"Collection" : cm2.isOptional() ? "Optional" : "Array"));
-                               ClassMeta<?> elementType = 
resolveType(pParams[0], cm2.getElementType(), cm.getElementType());
+                               var elementType = resolveType(pParams[0], 
cm2.getElementType(), cm.getElementType());
                                if (elementType.isObject())
                                        return cm2;
                                return new ClassMeta<>(cm2, null, null, 
elementType);
@@ -4416,7 +4470,7 @@ public class BeanContext extends Context {
 
                if (o instanceof ParameterizedType o2) {
                        if (! o2.getRawType().equals(Enum.class)) {
-                               List<ClassMeta<?>> l = new LinkedList<>();
+                               var l = new LinkedList<ClassMeta<?>>();
                                for (var pt2 : o2.getActualTypeArguments()) {
                                        if (pt2 instanceof WildcardType || pt2 
instanceof TypeVariable)
                                                return null;
@@ -4482,20 +4536,20 @@ public class BeanContext extends Context {
                        return resolveClassMeta(ci.innerType(), typeVars);
                }
 
-               Class<?> c = TypeVariables.resolve(o, typeVars);
+               var c = TypeVariables.resolve(o, typeVars);
 
                // This can happen when trying to resolve the "E getFirst()" 
method on LinkedList, whose type is a TypeVariable
                // These should just resolve to Object.
                if (c == null)
                        return object();
 
-               ClassMeta rawType = getClassMeta(c);
+               var rawType = getClassMeta(c);
 
                // If this is a Map or Collection, and the parameter types 
aren't part
                // of the class definition itself (e.g. class AddressBook 
extends List<Person>),
                // then we need to figure out the parameters.
                if (rawType.isMap() || rawType.isCollection() || 
rawType.isOptional()) {
-                       ClassMeta[] params = findParameters(o, c);
+                       var params = findParameters(o, c);
                        if (params == null)
                                return rawType;
                        if (rawType.isMap()) {
@@ -4512,7 +4566,7 @@ public class BeanContext extends Context {
 
                if (rawType.isArray()) {
                        if (o instanceof GenericArrayType o2) {
-                               ClassMeta elementType = 
resolveClassMeta(o2.getGenericComponentType(), typeVars);
+                               var elementType = 
resolveClassMeta(o2.getGenericComponentType(), typeVars);
                                return new ClassMeta(rawType, null, null, 
elementType);
                        }
                }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContextable.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContextable.java
index 7afda4b6cc..57cc48236f 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContextable.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContextable.java
@@ -358,7 +358,7 @@ public abstract class BeanContextable extends Context {
                 * @return This object.
                 */
                public Builder beanDictionary(Class<?>...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        bcBuilder.beanDictionary(values);
                        return this;
                }
@@ -1465,7 +1465,7 @@ public abstract class BeanContextable extends Context {
                 * @return This object.
                 */
                public Builder dictionaryOn(Class<?> on, Class<?>...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        bcBuilder.dictionaryOn(assertArgNotNull("on", on), 
values);
                        return this;
                }
@@ -1849,7 +1849,7 @@ public abstract class BeanContextable extends Context {
                        return HashKey.of(
                                super.hashKey(),
                                bcBuilder.hashKey(),
-                               bc == null ? 0 : bc.hashKey
+                               bc == null ? 0 : bc.getHashKey()
                        );
                        // @formatter:on
                }
@@ -2161,7 +2161,7 @@ public abstract class BeanContextable extends Context {
                 * @return This object.
                 */
                public Builder interfaces(Class<?>...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        bcBuilder.interfaces(value);
                        return this;
                }
@@ -2310,7 +2310,7 @@ public abstract class BeanContextable extends Context {
                 * @return This object.
                 */
                public Builder notBeanClasses(Class<?>...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        bcBuilder.notBeanClasses(values);
                        return this;
                }
@@ -2357,7 +2357,7 @@ public abstract class BeanContextable extends Context {
                 * @return This object.
                 */
                public Builder notBeanPackages(String...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        bcBuilder.notBeanPackages(values);
                        return this;
                }
@@ -2534,7 +2534,7 @@ public abstract class BeanContextable extends Context {
                 * @return This object.
                 */
                public Builder sortProperties(Class<?>...on) {
-                       assertVarargsNotNull("on", on);
+                       assertArgNoNulls("on", on);
                        bcBuilder.sortProperties(on);
                        return this;
                }
@@ -2656,7 +2656,7 @@ public abstract class BeanContextable extends Context {
                 * @return This object.
                 */
                public Builder swaps(Class<?>...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        bcBuilder.swaps(values);
                        return this;
                }
@@ -2748,7 +2748,7 @@ public abstract class BeanContextable extends Context {
                 * @return This object.
                 */
                public Builder swaps(Object...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        bcBuilder.swaps(values);
                        return this;
                }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
index d228e9e0f8..bf1a543e4a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
@@ -1196,13 +1196,13 @@ public class BeanMeta<T> {
         */
        private BeanRegistry findBeanRegistry() {
                // Bean dictionary on bean filter.
-               var beanDictionaryClasses = opt(beanFilter).map(x -> 
(List<ClassInfo>)copyOf(x.getBeanDictionary())).orElse(list());
+               var beanDictionaryClasses = opt(beanFilter).map(x -> new 
ArrayList<>(x.getBeanDictionary())).orElse(new ArrayList<>());
 
                // Bean dictionary from @Bean(typeName) annotation.
                var ba = beanContext.getAnnotationProvider().find(Bean.class, 
classMeta);
                ba.stream().map(x -> 
x.inner().typeName()).filter(Utils::isNotEmpty).findFirst().ifPresent(x -> 
beanDictionaryClasses.add(classMeta));
 
-               return new BeanRegistry(beanContext, null, 
beanDictionaryClasses.stream().map(ClassInfo::inner).toArray(Class<?>[]::new));
+               return new BeanRegistry(beanContext, null, 
beanDictionaryClasses);
        }
 
        /*
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
index 30a8983d92..a833496b54 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
@@ -36,6 +36,7 @@ import org.apache.juneau.annotation.*;
 import org.apache.juneau.collections.*;
 import org.apache.juneau.commons.collections.*;
 import org.apache.juneau.commons.reflect.*;
+import org.apache.juneau.commons.reflect.ReflectionUtils;
 import org.apache.juneau.cp.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.parser.*;
@@ -351,7 +352,7 @@ public class BeanPropertyMeta implements 
Comparable<BeanPropertyMeta> {
                        if (rawTypeMeta == null)
                                return false;
 
-                       beanRegistry = new BeanRegistry(bc, parentBeanRegistry, 
bdClasses.toArray(new Class<?>[0]));
+                       beanRegistry = new BeanRegistry(bc, parentBeanRegistry, 
bdClasses.stream().map(ReflectionUtils::info).toList());
 
                        isDyna = "*".equals(name);
 
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyValue.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyValue.java
index d4e5e1021e..d0572a6b80 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyValue.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyValue.java
@@ -23,7 +23,6 @@ import org.apache.juneau.commons.collections.*;
 
 /**
  * Represents a simple bean property value and the meta-data associated with 
it.
- *
  */
 public class BeanPropertyValue implements Comparable<BeanPropertyValue> {
 
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanProxyInvocationHandler.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanProxyInvocationHandler.java
index 9165bb3c32..0780120161 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanProxyInvocationHandler.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanProxyInvocationHandler.java
@@ -26,14 +26,51 @@ import java.util.*;
 import org.apache.juneau.json.*;
 
 /**
- * Provides an {@link InvocationHandler} for creating beans from bean 
interfaces.
+ * Provides an {@link InvocationHandler} for creating dynamic proxy instances 
of bean interfaces.
  *
  * <p>
- * If the {@code useInterfaceProxies} setting is enabled in {@link 
BeanContext}, this is the class that creates
- * instances of beans from interfaces.
+ * This class enables the creation of bean instances from interfaces without 
requiring concrete implementations.
+ * When the {@code useInterfaceProxies} setting is enabled in {@link 
BeanContext}, this handler is used to create
+ * proxy instances that implement bean interfaces.
  *
+ * <p>
+ * The handler stores bean property values in an internal map and intercepts 
method calls to:
+ * <ul>
+ *     <li><b>Getter methods</b> - Returns values from the internal property 
map</li>
+ *     <li><b>Setter methods</b> - Stores values in the internal property 
map</li>
+ *     <li><b>{@code equals(Object)}</b> - Compares property maps, with 
special handling for other proxy instances</li>
+ *     <li><b>{@code hashCode()}</b> - Returns hash code based on the property 
map</li>
+ *     <li><b>{@code toString()}</b> - Serializes the property map to JSON</li>
+ * </ul>
+ *
+ * <p>
+ * When comparing two proxy instances using {@code equals()}, if both are 
created with {@code BeanProxyInvocationHandler},
+ * the comparison is optimized by directly comparing their internal property 
maps rather than converting to {@link BeanMap}.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bjava'>
+ *     <jc>// Define an interface</jc>
+ *     <jk>public interface</jk> Person {
+ *             <jk>String</jk> <jsm>getName</jsm>();
+ *             <jk>void</jk> <jsm>setName</jsm>(<jk>String</jk> name);
+ *             <jk>int</jk> <jsm>getAge</jsm>();
+ *             <jk>void</jk> <jsm>setAge</jsm>(<jk>int</jk> age);
+ *     }
+ *
+ *     <jc>// Create a proxy instance</jc>
+ *     <jk>var</jk> bc = 
<jsm>BeanContext</jsm>.<jsm>create</jsm>().<jsm>useInterfaceProxies</jsm>().<jsm>build</jsm>();
+ *     <jk>var</jk> person = 
bc.<jsm>getClassMeta</jsm>(Person.<jk>class</jk>).<jsm>newInstance</jsm>();
  *
- * @param <T> The interface class
+ *     <jc>// Use it like a regular bean</jc>
+ *     person.<jsm>setName</jsm>(<js>"John"</js>);
+ *     person.<jsm>setAge</jsm>(25);
+ *     <jk>var</jk> name = person.<jsm>getName</jsm>(); <jc>// Returns 
"John"</jc>
+ * </p>
+ *
+ * @param <T> The interface class type
+ * @see BeanContext#isUseInterfaceProxies()
+ * @see BeanMeta#getBeanProxyInvocationHandler()
+ * @see Proxy#newProxyInstance(ClassLoader, Class[], InvocationHandler)
  */
 public class BeanProxyInvocationHandler<T> implements InvocationHandler {
 
@@ -41,9 +78,9 @@ public class BeanProxyInvocationHandler<T> implements 
InvocationHandler {
        private Map<String,Object> beanProps;           // The map of property 
names to bean property values.
 
        /**
-        * Constructs with the specified {@link BeanMeta}.
+        * Constructor.
         *
-        * @param meta The bean meta data.
+        * @param meta The bean metadata for the interface. Must not be 
<jk>null</jk>.
         */
        public BeanProxyInvocationHandler(BeanMeta<T> meta) {
                this.meta = meta;
@@ -51,25 +88,46 @@ public class BeanProxyInvocationHandler<T> implements 
InvocationHandler {
        }
 
        /**
-        * Implemented to handle the method called.
+        * Handles method invocations on the proxy instance.
+        *
+        * <p>
+        * This method intercepts all method calls on the proxy and routes them 
appropriately:
+        * <ul>
+        *      <li>If the method is {@code equals(Object)}, compares property 
maps</li>
+        *      <li>If the method is {@code hashCode()}, returns the hash code 
of the property map</li>
+        *      <li>If the method is {@code toString()}, serializes the 
property map to JSON</li>
+        *      <li>If the method is a getter (identified via {@link 
BeanMeta#getGetterProps()}), returns the property value</li>
+        *      <li>If the method is a setter (identified via {@link 
BeanMeta#getSetterProps()}), stores the property value</li>
+        *      <li>Otherwise, throws {@link UnsupportedOperationException}</li>
+        * </ul>
+        *
+        * <p>
+        * The {@code equals()} method has special optimization: when comparing 
two proxy instances created with this handler,
+        * it directly compares their internal property maps using {@link 
Proxy#getInvocationHandler(Object)} to access the
+        * other instance's handler.
+        *
+        * @param proxy The proxy instance on which the method was invoked
+        * @param method The method that was invoked
+        * @param args The arguments passed to the method, or <jk>null</jk> if 
no arguments
+        * @return The return value of the method invocation
+        * @throws UnsupportedOperationException If the method is not a 
supported bean method (getter, setter, equals, hashCode, or toString)
         */
        @Override /* Overridden from InvocationHandler */
        public Object invoke(Object proxy, Method method, Object[] args) {
                var mi = info(method);
-               if (mi.hasName("equals") && 
mi.hasParameterTypes(java.lang.Object.class)) {
-                       Object arg = args[0];
+               if (mi.hasName("equals") && mi.hasParameterTypes(Object.class)) 
{
+                       var arg = args[0];
                        if (arg == null)
                                return false;
                        if (proxy == arg)
                                return true;
-                       if (proxy.getClass() == arg.getClass()) {
-                               InvocationHandler ih = 
Proxy.getInvocationHandler(arg);
+                       if (eq(proxy.getClass(), arg.getClass())) {
+                               var ih = Proxy.getInvocationHandler(arg);
                                if (ih instanceof BeanProxyInvocationHandler 
ih2) {
-                                       return 
this.beanProps.equals(ih2.beanProps);
+                                       return beanProps.equals(ih2.beanProps);
                                }
                        }
-                       BeanMap<Object> bean = 
this.meta.getBeanContext().toBeanMap(arg);
-                       return this.beanProps.equals(bean);
+                       return eq(beanProps, 
meta.getBeanContext().toBeanMap(arg));
                }
 
                if (mi.hasName("hashCode") && mi.getParameterCount() == 0)
@@ -78,13 +136,13 @@ public class BeanProxyInvocationHandler<T> implements 
InvocationHandler {
                if (mi.hasName("toString") && mi.getParameterCount() == 0)
                        return Json5Serializer.DEFAULT.toString(this.beanProps);
 
-               String prop = this.meta.getGetterProps().get(method);
+               var prop = meta.getGetterProps().get(method);
                if (nn(prop))
-                       return this.beanProps.get(prop);
+                       return beanProps.get(prop);
 
-               prop = this.meta.getSetterProps().get(method);
+               prop = meta.getSetterProps().get(method);
                if (nn(prop)) {
-                       this.beanProps.put(prop, args[0]);
+                       beanProps.put(prop, args[0]);
                        return null;
                }
 
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanRegistry.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanRegistry.java
index 7f0edc94fa..16489a2813 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanRegistry.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanRegistry.java
@@ -17,6 +17,7 @@
 package org.apache.juneau;
 
 import static org.apache.juneau.commons.reflect.ReflectionUtils.*;
+import static org.apache.juneau.commons.utils.AssertionUtils.*;
 import static org.apache.juneau.commons.utils.CollectionUtils.*;
 import static org.apache.juneau.commons.utils.ThrowableUtils.*;
 import static org.apache.juneau.commons.utils.Utils.*;
@@ -58,8 +59,9 @@ public class BeanRegistry {
        private final AnnotationProvider ap;
        private final boolean isEmpty;
 
-       // TODO - Convert classes to use ClassInfo.
-       BeanRegistry(BeanContext bc, BeanRegistry parent, Class<?>...classes) {
+       BeanRegistry(BeanContext bc, BeanRegistry parent, List<ClassInfo> 
classes) {
+               assertArgNotNull("bc", bc);
+               assertArgNotNull("classes", classes);
                this.bc = bc;
                this.ap = bc.getAnnotationProvider();
                this.map = new ConcurrentHashMap<>();
@@ -67,8 +69,7 @@ public class BeanRegistry {
                bc.getBeanDictionary().forEach(this::addClass);
                if (nn(parent))
                        parent.map.forEach(this::addToMap);
-               for (var c : classes)
-                       addClass(c);
+               classes.forEach(this::addClass);
                isEmpty = map.isEmpty();
        }
 
@@ -128,17 +129,16 @@ public class BeanRegistry {
                return r(properties());
        }
 
-       private void addClass(Class<?> c) {
+       private void addClass(ClassInfo ci) {
                try {
-                       if (nn(c)) {
-                               var ci = info(c);
+                       if (nn(ci) && nn(ci.inner())) {
                                if (ci.isChildOf(Collection.class)) {
                                        Collection<?> cc = 
BeanCreator.of(Collection.class).type(ci).run();
                                        cc.forEach(x -> {
-                                               if (x instanceof Class x2)
-                                                       addClass(x2);
+                                               if (x instanceof Class<?> x2)
+                                                       addClass(info(x2));
                                                else
-                                                       throw bex("Collection 
class ''{0}'' passed to BeanRegistry does not contain Class objects.", cn(c));
+                                                       throw bex("Collection 
class ''{0}'' passed to BeanRegistry does not contain Class objects.", 
ci.getName());
                                        });
                                } else if (ci.isChildOf(Map.class)) {
                                        Map<?,?> m = 
BeanCreator.of(Map.class).type(ci).run();
@@ -150,7 +150,7 @@ public class BeanRegistry {
                                                else if (isArray(v))
                                                        val = 
getTypedClassMeta(v);
                                                else
-                                                       throw bex("Class 
''{0}'' was passed to BeanRegistry but value of type ''{1}'' found in map is 
not a Type object.", cn(c), cn(v));
+                                                       throw bex("Class 
''{0}'' was passed to BeanRegistry but value of type ''{1}'' found in map is 
not a Type object.", ci.getName(), cn(v));
                                                addToMap(typeName, val);
                                        });
                                } else {
@@ -160,9 +160,9 @@ public class BeanRegistry {
                                                .map(x -> x.inner().typeName())
                                                .filter(Utils::isNotEmpty)
                                                .findFirst()
-                                               .orElseThrow(() -> bex("Class 
''{0}'' was passed to BeanRegistry but it doesn't have a @Bean(typeName) 
annotation defined.", cn(c)));
+                                               .orElseThrow(() -> bex("Class 
''{0}'' was passed to BeanRegistry but it doesn't have a @Bean(typeName) 
annotation defined.", ci.getName()));
                                        // @formatter:on
-                                       addToMap(typeName, bc.getClassMeta(c));
+                                       addToMap(typeName, 
bc.getClassMeta(ci.inner()));
                                }
                        }
                } catch (BeanRuntimeException e) {
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
index b4bbbef1fa..9d17da9ead 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
@@ -72,9 +72,9 @@ public class BeanSession extends ContextSession {
                protected Builder(BeanContext ctx) {
                        super(assertArgNotNull("ctx", ctx));
                        this.ctx = ctx;
-                       locale = ctx.locale;
-                       mediaType = ctx.mediaType;
-                       timeZone = ctx.timeZone;
+                       locale = ctx.getLocale();
+                       mediaType = ctx.getMediaType();
+                       timeZone = ctx.getTimeZone();
                }
 
                @Override /* Overridden from Builder */
@@ -535,8 +535,10 @@ public class BeanSession extends ContextSession {
         * @see BeanContext.Builder#beanDictionary(Class...)
         * @return
         *      The list of classes that make up the bean dictionary in this 
bean context.
+        *      <br>Never <jk>null</jk>.
+        *      <br>List is unmodifiable.
         */
-       public final List<Class<?>> getBeanDictionary() { return 
ctx.getBeanDictionary(); }
+       public final List<ClassInfo> getBeanDictionary() { return 
ctx.getBeanDictionary(); }
 
        /**
         * Minimum bean field visibility.
@@ -714,20 +716,24 @@ public class BeanSession extends ContextSession {
        /**
         * Bean class exclusions.
         *
-        * @see BeanContext.Builder#notBeanClasses(Class...)
+        * @see BeanContext.Builder#notBeanClasses(ClassInfo...)
         * @return
         *      The list of classes that are explicitly not beans.
+        *      <br>Never <jk>null</jk>.
+        *      <br>List is unmodifiable.
         */
-       public final Class<?>[] getNotBeanClasses() { return 
ctx.getNotBeanClasses(); }
+       public final List<ClassInfo> getNotBeanClasses() { return 
ctx.getNotBeanClasses(); }
 
        /**
         * Bean package exclusions.
         *
         * @see BeanContext.Builder#notBeanPackages(String...)
         * @return
-        *      The list of fully-qualified package names to exclude from being 
classified as beans.
+        *      The set of fully-qualified package names to exclude from being 
classified as beans.
+        *      <br>Never <jk>null</jk>.
+        *      <br>Set is unmodifiable.
         */
-       public final String[] getNotBeanPackagesNames() { return 
ctx.getNotBeanPackagesNames(); }
+       public final Set<String> getNotBeanPackagesNames() { return 
ctx.getNotBeanPackagesNames(); }
 
        /**
         * Bean property namer.
@@ -744,8 +750,10 @@ public class BeanSession extends ContextSession {
         * @see BeanContext.Builder#swaps(Class...)
         * @return
         *      The list POJO swaps defined.
+        *      <br>Never <jk>null</jk>.
+        *      <br>List is unmodifiable.
         */
-       public final ObjectSwap<?,?>[] getSwaps() { return ctx.getSwaps(); }
+       public final List<ObjectSwap<?,?>> getSwaps() { return ctx.getSwaps(); }
 
        /**
         * Time zone.
@@ -1626,8 +1634,10 @@ public class BeanSession extends ContextSession {
         * @see BeanContext.Builder#notBeanPackages(String...)
         * @return
         *      The list of package name prefixes to exclude from being 
classified as beans.
+        *      <br>Never <jk>null</jk>.
+        *      <br>List is unmodifiable.
         */
-       protected final String[] getNotBeanPackagesPrefixes() { return 
ctx.getNotBeanPackagesPrefixes(); }
+       protected final List<String> getNotBeanPackagesPrefixes() { return 
ctx.getNotBeanPackagesPrefixes(); }
 
        /**
         * Creates either an {@link JsonMap} or {@link LinkedHashMap} depending 
on whether the key type is
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
index cd558edac0..32088e60f1 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
@@ -185,8 +185,8 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                this.cat = new Categories();
 
                // We always immediately add this class meta to the bean 
context cache so that we can resolve recursive references.
-               if (nn(beanContext) && nn(beanContext.cmCache) && 
isCacheable(innerClass))
-                       beanContext.cmCache.put(innerClass, this);
+               if (nn(beanContext) && nn(beanContext.getCmCache()) && 
isCacheable(innerClass))
+                       beanContext.getCmCache().put(innerClass, this);
 
                var ap = beanContext.getAnnotationProvider();
 
@@ -1359,7 +1359,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
 
                var list = new ArrayList<ObjectSwap<T,?>>();
                var swapArray = beanContext.getSwaps();
-               if (swapArray != null && swapArray.length > 0) {
+               if (! swapArray.isEmpty()) {
                        var innerClass = inner();
                        for (var f : swapArray)
                                if (f.getNormalClass().isParentOf(innerClass))
@@ -1388,7 +1388,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                if (beanContext == null)
                        return l();
                var swapArray = beanContext.getSwaps();
-               if (swapArray == null || swapArray.length == 0)
+               if (swapArray.isEmpty())
                        return l();
                var list = new ArrayList<ObjectSwap<?,?>>();
                var innerClass = inner();
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
index a4fa7d68b8..01f550d722 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
@@ -302,7 +302,7 @@ public abstract class Context {
                 * @return This object.
                 */
                public Builder annotations(Annotation...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        annotations.addAll(l(values));
                        return this;
                }
@@ -312,11 +312,11 @@ public abstract class Context {
                 *
                 * @param values
                 *      The annotations to register with the context.
-                *      <br>Cannot be <jk>null</jk>.
+                *      <br>Cannot be <jk>null</jk> or contain <jk>null</jk> 
values.
                 * @return This object.
                 */
                public Builder annotations(List<Annotation> values) {
-                       annotations.addAll(assertArgNotNull("values", values));
+                       annotations.addAll(assertArgNoNulls("values", values));
                        return this;
                }
 
@@ -364,7 +364,7 @@ public abstract class Context {
                 * @return This object.
                 */
                public Builder applyAnnotations(Class<?>...from) {
-                       assertVarargsNotNull("from", from);
+                       assertArgNoNulls("from", from);
                        return applyAnnotations((Object[])from);
                }
 
@@ -452,7 +452,7 @@ public abstract class Context {
                 * @return This object.
                 */
                public Builder applyAnnotations(Object...from) {
-                       assertVarargsNotNull("from", from);
+                       assertArgNoNulls("from", from);
                        var work = AnnotationWorkList.create();
                        Arrays.stream(from).forEach(x -> traverse(work, x));
                        return apply(work);
@@ -693,7 +693,7 @@ public abstract class Context {
                 *      <br>Cannot contain <jk>null</jk> values.
                 */
                protected void registerBuilders(Object...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        for (var b : values) {
                                if (b == this)
                                        builders.add(b);
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextSession.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextSession.java
index c6d65930ae..1d0d1c1edc 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextSession.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextSession.java
@@ -197,7 +197,7 @@ public abstract class ContextSession {
                        return;
                if (warnings == null)
                        warnings = new LinkedList<>();
-               warnings.add((warnings.size() + 1) + ": " + 
f(assertArgNotNull("msg", msg), assertVarargsNotNull("args", args)));
+               warnings.add((warnings.size() + 1) + ": " + 
f(assertArgNotNull("msg", msg), assertArgNoNulls("args", args)));
        }
 
        /**
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/BaseHttpPartParser.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/BaseHttpPartParser.java
index c16a3b4134..6adfb3aea1 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/BaseHttpPartParser.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/BaseHttpPartParser.java
@@ -141,7 +141,7 @@ public abstract class BaseHttpPartParser extends 
BeanContextable implements Http
         * @throws SchemaValidationException If the input or resulting HTTP 
part object fails schema validation.
         */
        public <T> T parse(HttpPartType partType, HttpPartSchema schema, String 
in, Type toType, Type...toTypeArgs) throws ParseException, 
SchemaValidationException {
-               assertVarargsNotNull("toTypeArgs", toTypeArgs);
+               assertArgNoNulls("toTypeArgs", toTypeArgs);
                return getPartSession().parse(partType, schema, in, 
getClassMeta(assertArgNotNull("toType", toType), toTypeArgs));
        }
 }
\ No newline at end of file
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGenerator.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGenerator.java
index 90b3a7bb58..fdeccf15c8 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGenerator.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGenerator.java
@@ -154,7 +154,7 @@ public class JsonSchemaGenerator extends 
BeanTraverseContext implements JsonSche
                 * @return This object.
                 */
                public Builder addDescriptionsTo(TypeCategory...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        addDescriptionsTo = addAll(addDescriptionsTo, values);
                        return this;
                }
@@ -194,7 +194,7 @@ public class JsonSchemaGenerator extends 
BeanTraverseContext implements JsonSche
                 * @return This object.
                 */
                public Builder addExamplesTo(TypeCategory...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        addExamplesTo = addAll(addExamplesTo, values);
                        return this;
                }
@@ -613,7 +613,7 @@ public class JsonSchemaGenerator extends 
BeanTraverseContext implements JsonSche
                 * @return This object.
                 */
                public Builder ignoreTypes(String...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        ignoreTypes = addAll(ignoreTypes, values);
                        return this;
                }
@@ -851,7 +851,7 @@ public class JsonSchemaGenerator extends 
BeanTraverseContext implements JsonSche
        private final BeanDefMapper beanDefMapperBean;
        private final Map<BeanPropertyMeta,JsonSchemaBeanPropertyMeta> 
jsonSchemaBeanPropertyMetas = new ConcurrentHashMap<>();
        private final Map<ClassMeta<?>,JsonSchemaClassMeta> 
jsonSchemaClassMetas = new ConcurrentHashMap<>();
-       private final Pattern[] ignoreTypePatterns;
+       private final List<Pattern> ignoreTypePatterns;
 
        /**
         * Constructor.
@@ -871,7 +871,7 @@ public class JsonSchemaGenerator extends 
BeanTraverseContext implements JsonSche
 
                Set<Pattern> ignoreTypePatterns = set();
                ignoreTypes.forEach(y -> split(y, x -> 
ignoreTypePatterns.add(Pattern.compile(x.replace(".", "\\.").replace("*", 
".*")))));
-               this.ignoreTypePatterns = ignoreTypePatterns.toArray(new 
Pattern[ignoreTypePatterns.size()]);
+               this.ignoreTypePatterns = u(new 
ArrayList<>(ignoreTypePatterns));
 
                try {
                        beanDefMapperBean = 
beanDefMapper.getDeclaredConstructor().newInstance();
@@ -899,8 +899,10 @@ public class JsonSchemaGenerator extends 
BeanTraverseContext implements JsonSche
         * @see Builder#ignoreTypes(String...)
         * @return
         *      Custom schema information for particular class types.
+        *      <br>Never <jk>null</jk>.
+        *      <br>List is unmodifiable.
         */
-       public List<Pattern> getIgnoreTypes() { return l(ignoreTypePatterns); }
+       public List<Pattern> getIgnoreTypes() { return ignoreTypePatterns; }
 
        @Override
        public JsonSchemaBeanPropertyMeta 
getJsonSchemaBeanPropertyMeta(BeanPropertyMeta bpm) {
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java
index 1f22387009..365772b0df 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java
@@ -997,7 +997,7 @@ public class Parser extends BeanContextable {
        protected final int debugOutputLines;
        protected final Class<? extends ParserListener> listener;
        protected final String consumes;
-       private final MediaType[] consumesArray;
+       private final List<MediaType> consumesArray;
 
        /**
         * Constructor.
@@ -1016,10 +1016,11 @@ public class Parser extends BeanContextable {
                unbuffered = builder.unbuffered;
 
                String[] _consumes = splita(nn(consumes) ? consumes : "");
-               this.consumesArray = new MediaType[_consumes.length];
-               for (var i = 0; i < _consumes.length; i++) {
-                       this.consumesArray[i] = MediaType.of(_consumes[i]);
+               List<MediaType> _consumesList = new ArrayList<>();
+               for (var consume : _consumes) {
+                       _consumesList.add(MediaType.of(consume));
                }
+               this.consumesArray = u(_consumesList);
        }
 
        /**
@@ -1074,14 +1075,14 @@ public class Parser extends BeanContextable {
         *
         * @return The list of media types.  Never <jk>null</jk>.
         */
-       public final List<MediaType> getMediaTypes() { return l(consumesArray); 
}
+       public final List<MediaType> getMediaTypes() { return consumesArray; }
 
        /**
         * Returns the first media type handled based on the values passed to 
the <c>consumes</c> constructor parameter.
         *
         * @return The media type.
         */
-       public final MediaType getPrimaryMediaType() { return consumesArray == 
null || consumesArray.length == 0 ? null : consumesArray[0]; }
+       public final MediaType getPrimaryMediaType() { return 
consumesArray.isEmpty() ? null : consumesArray.get(0); }
 
        @Override /* Overridden from Context */
        public ParserSession getSession() { return createSession().build(); }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/Serializer.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/Serializer.java
index 985fa175fb..66e08d51f4 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/Serializer.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/Serializer.java
@@ -1292,7 +1292,7 @@ public class Serializer extends BeanTraverseContext {
        protected final UriRelativity uriRelativity;
        protected final UriResolution uriResolution;
        private final MediaRanges acceptRanges;
-       private final MediaType[] acceptMediaTypes;
+       private final List<MediaType> acceptMediaTypes;
        private final MediaType producesMediaType;
 
        /**
@@ -1320,7 +1320,7 @@ public class Serializer extends BeanTraverseContext {
 
                this.producesMediaType = MediaType.of(produces);
                this.acceptRanges = nn(accept) ? MediaRanges.of(accept) : 
MediaRanges.of(produces);
-               this.acceptMediaTypes = nn(builder.accept) ? 
MediaType.ofAll(splita(builder.accept)) : a(this.producesMediaType);
+               this.acceptMediaTypes = u(nn(builder.accept) ? 
l(MediaType.ofAll(splita(builder.accept))) : l(this.producesMediaType));
        }
 
        @Override /* Overridden from Context */
@@ -1366,7 +1366,7 @@ public class Serializer extends BeanTraverseContext {
         *
         * @return The media type.  Never <jk>null</jk>.
         */
-       public final MediaType getPrimaryMediaType() { return 
acceptMediaTypes[0]; }
+       public final MediaType getPrimaryMediaType() { return 
acceptMediaTypes.get(0); }
 
        /**
         * Optional method that returns the response <c>Content-Type</c> for 
this serializer if it is different from
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java
index ba4caff303..b829ea149a 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java
@@ -182,7 +182,7 @@ public class XmlSerializer extends WriterSerializer 
implements XmlMetaProvider {
                        disableAutoDetectNamespaces = 
copyFrom.disableAutoDetectNamespaces;
                        disableJsonTags = copyFrom.disableJsonTags;
                        enableNamespaces = copyFrom.enableNamespaces;
-                       namespaces = copyOf(copyFrom.namespaces);
+                       namespaces = copyFrom.namespaces == null ? null : new 
ArrayList<>(copyFrom.namespaces);
                        textNodeDelimiter = copyFrom.textNodeDelimiter;
                }
 
@@ -200,7 +200,7 @@ public class XmlSerializer extends WriterSerializer 
implements XmlMetaProvider {
                        disableAutoDetectNamespaces = ! 
copyFrom.autoDetectNamespaces;
                        disableJsonTags = ! copyFrom.addJsonTags;
                        enableNamespaces = copyFrom.enableNamespaces;
-                       namespaces = copyFrom.namespaces.length == 0 ? null : 
list(copyFrom.namespaces);
+                       namespaces = copyFrom.namespaces.isEmpty() ? null : new 
ArrayList<>(copyFrom.namespaces);
                        textNodeDelimiter = copyFrom.textNodeDelimiter;
                }
 
@@ -826,7 +826,7 @@ public class XmlSerializer extends WriterSerializer 
implements XmlMetaProvider {
                 * @return This object.
                 */
                public Builder namespaces(Namespace...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        namespaces = addAll(namespaces, values);
                        return this;
                }
@@ -1185,7 +1185,6 @@ public class XmlSerializer extends WriterSerializer 
implements XmlMetaProvider {
                }
        }
 
-       private static final Namespace[] EMPTY_NAMESPACE_ARRAY = {};
 
        /** Default serializer without namespaces. */
        public static final XmlSerializer DEFAULT = new XmlSerializer(create());
@@ -1222,7 +1221,7 @@ public class XmlSerializer extends WriterSerializer 
implements XmlMetaProvider {
        protected final boolean autoDetectNamespaces;
        protected final boolean enableNamespaces;
        protected final Namespace defaultNamespace;
-       protected final Namespace[] namespaces;
+       protected final List<Namespace> namespaces;
        protected final String textNodeDelimiter;
 
        private final boolean addBeanTypes;
@@ -1244,7 +1243,7 @@ public class XmlSerializer extends WriterSerializer 
implements XmlMetaProvider {
                autoDetectNamespaces = ! builder.disableAutoDetectNamespaces;
                defaultNamespace = nn(builder.defaultNamespace) ? 
builder.defaultNamespace : DEFAULT_JUNEAU_NAMESPACE;
                enableNamespaces = builder.enableNamespaces;
-               namespaces = nn(builder.namespaces) ? 
builder.namespaces.toArray(EMPTY_NAMESPACE_ARRAY) : EMPTY_NAMESPACE_ARRAY;
+               namespaces = u(nn(builder.namespaces) ? new 
ArrayList<>(builder.namespaces) : new ArrayList<>());
                textNodeDelimiter = builder.textNodeDelimiter;
                addBeanTypes = addBeanTypesXml || super.isAddBeanTypes();
        }
@@ -1307,8 +1306,10 @@ public class XmlSerializer extends WriterSerializer 
implements XmlMetaProvider {
         * @see Builder#namespaces(Namespace...)
         * @return
         *      The default list of namespaces associated with this serializer.
+        *      <br>Never <jk>null</jk>.
+        *      <br>List is unmodifiable.
         */
-       protected final Namespace[] getNamespaces() { return namespaces; }
+       protected final List<Namespace> getNamespaces() { return namespaces; }
 
        /**
         * Add <js>"_type"</js> properties when needed.
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
index 905ec070c2..19d581dda0 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
@@ -243,7 +243,7 @@ public class XmlSerializerSession extends 
WriterSerializerSession {
        private final String textNodeDelimiter;
        private final XmlSerializer ctx;
        private Namespace defaultNamespace;
-       private Namespace[] namespaces = {};
+       private List<Namespace> namespaces = new ArrayList<>();
 
        /**
         * Constructor.
@@ -254,7 +254,8 @@ public class XmlSerializerSession extends 
WriterSerializerSession {
                super(builder);
                ctx = builder.ctx;
                defaultNamespace = 
findDefaultNamespace(ctx.getDefaultNamespace());
-               namespaces = ctx.getNamespaces();
+               var ctxNamespaces = ctx.getNamespaces();
+               namespaces = ctxNamespaces == null ? new ArrayList<>() : new 
ArrayList<>(ctxNamespaces);
                textNodeDelimiter = ctx.textNodeDelimiter;
        }
 
@@ -676,8 +677,10 @@ public class XmlSerializerSession extends 
WriterSerializerSession {
         * @see XmlSerializer.Builder#namespaces(Namespace...)
         * @return
         *      The default list of namespaces associated with this serializer.
+        *      <br>Never <jk>null</jk>.
+        *      <br>List is modifiable (namespaces can be added during 
serialization).
         */
-       protected final Namespace[] getNamespaces() { return namespaces; }
+       protected final List<Namespace> getNamespaces() { return namespaces == 
null ? l() : namespaces; }
 
        /**
         * Add <js>"_type"</js> properties when needed.
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
index 3e6951c123..a932d3de18 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
@@ -3972,7 +3972,7 @@ public class RestClient extends BeanContextable 
implements HttpClient, Closeable
                 */
                @SuppressWarnings("unchecked")
                public Builder parsers(Class<? extends Parser>...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        parsers().add(value);
                        return this;
                }
@@ -4011,7 +4011,7 @@ public class RestClient extends BeanContextable 
implements HttpClient, Closeable
                 * @return This object.
                 */
                public Builder parsers(Parser...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        parsers().add(value);
                        return this;
                }
@@ -4834,7 +4834,7 @@ public class RestClient extends BeanContextable 
implements HttpClient, Closeable
                 */
                @SuppressWarnings("unchecked")
                public Builder serializers(Class<? extends Serializer>...value) 
{
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        serializers().add(value);
                        return this;
                }
@@ -4873,7 +4873,7 @@ public class RestClient extends BeanContextable 
implements HttpClient, Closeable
                 * @return This object.
                 */
                public Builder serializers(Serializer...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        serializers().add(value);
                        return this;
                }
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequest.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequest.java
index 64ff1553dc..af112d3f39 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequest.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequest.java
@@ -1225,7 +1225,7 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
         * @throws RestCallException If init method on interceptor threw an 
exception.
         */
        public RestRequest interceptors(RestCallInterceptor...interceptors) 
throws RestCallException {
-               assertVarargsNotNull("interceptors", interceptors);
+               assertArgNoNulls("interceptors", interceptors);
                try {
                        for (var i : interceptors) {
                                this.interceptors.add(i);
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 3dc12d9983..f8eafc4c70 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
@@ -865,7 +865,7 @@ public class RestContext extends Context {
                 * @return This object.
                 */
                public Builder children(Object...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        addAll(children, values);
                        return this;
                }
@@ -1056,7 +1056,7 @@ public class RestContext extends Context {
                 * @return This object.
                 */
                public Builder consumes(MediaType...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        consumes = addAll(consumes, values);
                        return this;
                }
@@ -1239,7 +1239,7 @@ public class RestContext extends Context {
                 * @see #defaultClasses()
                 */
                public Builder defaultClasses(Class<?>...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        defaultClasses().add(values);
                        return this;
                }
@@ -1319,7 +1319,7 @@ public class RestContext extends Context {
                 * @return This object.
                 */
                public Builder 
defaultRequestAttributes(NamedAttribute...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        defaultRequestAttributes().add(values);
                        return this;
                }
@@ -1392,7 +1392,7 @@ public class RestContext extends Context {
                 * @return This object.
                 */
                public Builder defaultRequestHeaders(Header...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        defaultRequestHeaders().setDefault(values);
                        return this;
                }
@@ -1461,7 +1461,7 @@ public class RestContext extends Context {
                 * @return This object.
                 */
                public Builder defaultResponseHeaders(Header...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        defaultResponseHeaders().setDefault(values);
                        return this;
                }
@@ -1627,7 +1627,7 @@ public class RestContext extends Context {
                 */
                @SafeVarargs
                public final Builder encoders(Class<? extends Encoder>...value) 
{
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        encoders().add(value);
                        return this;
                }
@@ -1651,7 +1651,7 @@ public class RestContext extends Context {
                 * @return This object.
                 */
                public Builder encoders(Encoder...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        encoders().add(value);
                        return this;
                }
@@ -2337,7 +2337,7 @@ public class RestContext extends Context {
                 */
                @SafeVarargs
                public final Builder parsers(Class<? extends Parser>...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        parsers().add(value);
                        return this;
                }
@@ -2361,7 +2361,7 @@ public class RestContext extends Context {
                 * @return This object.
                 */
                public Builder parsers(Parser...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        parsers().add(value);
                        return this;
                }
@@ -2690,7 +2690,7 @@ public class RestContext extends Context {
                 * @return This object.
                 */
                public Builder produces(MediaType...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        produces = addAll(produces, values);
                        return this;
                }
@@ -2867,7 +2867,7 @@ public class RestContext extends Context {
                 */
                @SafeVarargs
                public final Builder responseProcessors(Class<? extends 
ResponseProcessor>...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        responseProcessors().add(value);
                        return this;
                }
@@ -2891,7 +2891,7 @@ public class RestContext extends Context {
                 * @return This object.
                 */
                public Builder responseProcessors(ResponseProcessor...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        responseProcessors().add(value);
                        return this;
                }
@@ -2993,7 +2993,7 @@ public class RestContext extends Context {
                 */
                @SafeVarargs
                public final Builder restOpArgs(Class<? extends 
RestOpArg>...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        restOpArgs().add(value);
                        return this;
                }
@@ -3161,7 +3161,7 @@ public class RestContext extends Context {
                 */
                @SafeVarargs
                public final Builder serializers(Class<? extends 
Serializer>...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        serializers().add(value);
                        return this;
                }
@@ -3185,7 +3185,7 @@ public class RestContext extends Context {
                 * @return This object.
                 */
                public Builder serializers(Serializer...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        serializers().add(value);
                        return this;
                }
@@ -3778,7 +3778,7 @@ public class RestContext extends Context {
                 */
                @SafeVarargs
                public final Builder vars(Class<? extends Var>...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        varResolver.vars(value);
                        return this;
                }
@@ -3802,7 +3802,7 @@ public class RestContext extends Context {
                 * @return This object.
                 */
                public Builder vars(Var...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        varResolver.vars(value);
                        return this;
                }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
index 1105253bdf..c34b8fa9bc 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
@@ -370,7 +370,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 * @return This object.
                 */
                public Builder consumes(MediaType...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        consumes = addAll(consumes, values);
                        return this;
                }
@@ -401,7 +401,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 */
                @SafeVarargs
                public final Builder converters(Class<? extends 
RestConverter>...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        converters().append(value);
                        return this;
                }
@@ -420,7 +420,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 * @return This object.
                 */
                public Builder converters(RestConverter...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        converters().append(value);
                        return this;
                }
@@ -540,7 +540,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 * @return This object.
                 */
                public Builder defaultRequestAttributes(NamedAttribute...value) 
{
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        defaultRequestAttributes().add(value);
                        return this;
                }
@@ -570,7 +570,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 * @return This object.
                 */
                public Builder defaultRequestFormData(NameValuePair...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        defaultRequestFormData().append(value);
                        return this;
                }
@@ -600,7 +600,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 * @return This object.
                 */
                public Builder 
defaultRequestHeaders(org.apache.http.Header...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        defaultRequestHeaders().append(value);
                        return this;
                }
@@ -630,7 +630,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 * @return This object.
                 */
                public Builder defaultRequestQueryData(NameValuePair...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        defaultRequestQueryData().append(value);
                        return this;
                }
@@ -660,7 +660,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 * @return This object.
                 */
                public Builder 
defaultResponseHeaders(org.apache.http.Header...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        defaultResponseHeaders().append(value);
                        return this;
                }
@@ -701,7 +701,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 */
                @SafeVarargs
                public final Builder encoders(Class<? extends Encoder>...value) 
{
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        encoders().add(value);
                        return this;
                }
@@ -720,7 +720,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 * @return This object.
                 */
                public Builder encoders(Encoder...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        encoders().add(value);
                        return this;
                }
@@ -751,7 +751,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 */
                @SafeVarargs
                public final Builder guards(Class<? extends RestGuard>...value) 
{
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        guards().append(value);
                        return this;
                }
@@ -770,7 +770,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 * @return This object.
                 */
                public Builder guards(RestGuard...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        guards().append(value);
                        return this;
                }
@@ -915,7 +915,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 */
                @SafeVarargs
                public final Builder matchers(Class<? extends 
RestMatcher>...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        matchers().append(value);
                        return this;
                }
@@ -934,7 +934,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 * @return This object.
                 */
                public Builder matchers(RestMatcher...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        matchers().append(value);
                        return this;
                }
@@ -1030,7 +1030,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 */
                @SafeVarargs
                public final Builder parsers(Class<? extends Parser>...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        parsers().add(value);
                        return this;
                }
@@ -1049,7 +1049,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 * @return This object.
                 */
                public Builder parsers(Parser...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        parsers().add(value);
                        return this;
                }
@@ -1168,7 +1168,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 * @return This object.
                 */
                public Builder path(String...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        path = prependAll(path, values);
                        return this;
                }
@@ -1201,7 +1201,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 * @return This object.
                 */
                public Builder produces(MediaType...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        produces = addAll(produces, values);
                        return this;
                }
@@ -1299,7 +1299,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 * @return This object.
                 */
                public Builder rolesDeclared(String...values) {
-                       assertVarargsNotNull("values", values);
+                       assertArgNoNulls("values", values);
                        rolesDeclared = addAll(rolesDeclared, values);
                        return this;
                }
@@ -1330,7 +1330,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 */
                @SafeVarargs
                public final Builder serializers(Class<? extends 
Serializer>...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        serializers().add(value);
                        return this;
                }
@@ -1349,7 +1349,7 @@ public class RestOpContext extends Context implements 
Comparable<RestOpContext>
                 * @return This object.
                 */
                public Builder serializers(Serializer...value) {
-                       assertVarargsNotNull("value", value);
+                       assertArgNoNulls("value", value);
                        serializers().add(value);
                        return this;
                }
diff --git a/juneau-utest/src/test/java/org/apache/juneau/BeanContext_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/BeanContext_Test.java
index bf4ebea05e..4c3d8506a9 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/BeanContext_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/BeanContext_Test.java
@@ -19,7 +19,11 @@ package org.apache.juneau;
 import static org.apache.juneau.TestUtils.*;
 import static org.junit.jupiter.api.Assertions.*;
 
+import java.util.Locale;
+import java.util.TimeZone;
+
 import org.apache.juneau.commons.reflect.*;
+import org.apache.juneau.commons.settings.Settings;
 import org.apache.juneau.json.*;
 import org.apache.juneau.testutils.pojos.*;
 import org.junit.jupiter.api.*;
@@ -29,6 +33,11 @@ class BeanContext_Test extends TestBase {
        BeanContext bc = BeanContext.DEFAULT;
        BeanSession bs = BeanContext.DEFAULT_SESSION;
 
+       @AfterEach
+       void tearDown() {
+               Settings.get().clearLocal();
+       }
+
        public interface A1 {
                int getF1();
                void setF1(int f1);
@@ -66,4 +75,104 @@ class BeanContext_Test extends TestBase {
                var p2 = JsonParser.create().ignoreUnknownEnumValues().build();
                assertNull(p2.parse("'UNKNOWN'", TestEnum.class));
        }
+
+       
//====================================================================================================
+       // BeanContext.Builder locale, mediaType, and timeZone from Settings
+       
//====================================================================================================
+
+       @Test void c01_locale_fromSettings() {
+               Settings.get().setLocal("BeanContext.locale", "fr-CA");
+               try {
+                       var bc = BeanContext.create().build();
+                       assertEquals(Locale.forLanguageTag("fr-CA"), 
bc.getLocale());
+               } finally {
+                       Settings.get().clearLocal();
+               }
+       }
+
+       @Test void c02_locale_defaultWhenNotSet() {
+               var bc = BeanContext.create().build();
+               assertEquals(Locale.getDefault(), bc.getLocale());
+       }
+
+       @Test void c03_mediaType_fromSettings() {
+               Settings.get().setLocal("BeanContext.mediaType", 
"application/json");
+               try {
+                       var bc = BeanContext.create().build();
+                       assertEquals(MediaType.of("application/json"), 
bc.getMediaType());
+               } finally {
+                       Settings.get().clearLocal();
+               }
+       }
+
+       @Test void c04_mediaType_nullWhenNotSet() {
+               var bc = BeanContext.create().build();
+               assertNull(bc.getMediaType());
+       }
+
+       @Test void c05_timeZone_fromSettings() {
+               Settings.get().setLocal("BeanContext.timeZone", 
"America/New_York");
+               try {
+                       var bc = BeanContext.create().build();
+                       assertEquals(TimeZone.getTimeZone("America/New_York"), 
bc.getTimeZone());
+               } finally {
+                       Settings.get().clearLocal();
+               }
+       }
+
+       @Test void c06_timeZone_nullWhenNotSet() {
+               var bc = BeanContext.create().build();
+               assertNull(bc.getTimeZone());
+       }
+
+       
//====================================================================================================
+       // BeanContext.copy() - Copy constructor coverage
+       
//====================================================================================================
+
+       @Test void d01_copy() {
+               // Create a BeanContext with some properties set to exercise 
the copy constructor
+               var original = BeanContext.create()
+                       .sortProperties()
+                       .locale(Locale.CANADA)
+                       .mediaType(MediaType.JSON)
+                       .timeZone(TimeZone.getTimeZone("America/New_York"))
+                       .build();
+
+               // Call copy() which uses the copy constructor 
Builder(BeanContext copyFrom)
+               // This exercises lines 273-277 which convert boolean fields 
from BeanContext to Builder disable flags
+               var builder = original.copy();
+
+               // Build a new context from the copied builder
+               var copied = builder.build();
+
+               // Verify the copied context has the same values
+               assertEquals(original.getBeanClassVisibility(), 
copied.getBeanClassVisibility());
+               assertEquals(original.getBeanConstructorVisibility(), 
copied.getBeanConstructorVisibility());
+               assertEquals(original.getBeanFieldVisibility(), 
copied.getBeanFieldVisibility());
+               assertEquals(original.getBeanMethodVisibility(), 
copied.getBeanMethodVisibility());
+               assertEquals(original.getBeanDictionary(), 
copied.getBeanDictionary());
+               assertEquals(original.getLocale(), copied.getLocale());
+               assertEquals(original.getMediaType(), copied.getMediaType());
+               assertEquals(original.getTimeZone(), copied.getTimeZone());
+       }
+
+       
//====================================================================================================
+       // BeanContext.Builder.impl() - Line 2372 coverage
+       
//====================================================================================================
+
+       @Test void e01_impl() {
+               // Create a BeanContext to use as the implementation
+               var impl = BeanContext.create()
+                       .sortProperties()
+                       .locale(Locale.CANADA)
+                       .build();
+
+               // Call impl() which exercises line 2372: super.impl(value);
+               var builder = BeanContext.create()
+                       .impl(impl);
+
+               // Build should return the pre-instantiated context
+               var result = builder.build();
+               assertSame(impl, result);
+       }
 }
\ No newline at end of file
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/BeanPropertyValue_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/BeanPropertyValue_Test.java
new file mode 100644
index 0000000000..6dec302000
--- /dev/null
+++ b/juneau-utest/src/test/java/org/apache/juneau/BeanPropertyValue_Test.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.juneau;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.*;
+
+class BeanPropertyValue_Test extends TestBase {
+
+       public static class TestBean {
+               public String name;
+               public int age;
+               public boolean active;
+       }
+
+       BeanContext bc = BeanContext.DEFAULT;
+
+       
//====================================================================================================
+       // compareTo() - Line 51 coverage
+       
//====================================================================================================
+
+       @Test void a01_compareTo_lessThan() {
+               var bm = bc.getBeanMeta(TestBean.class);
+               var pMeta1 = bm.getPropertyMeta("active");
+               var pMeta2 = bm.getPropertyMeta("age");
+
+               var pv1 = new BeanPropertyValue(pMeta1, "active", true, null);
+               var pv2 = new BeanPropertyValue(pMeta2, "age", 25, null);
+
+               assertTrue(pv1.compareTo(pv2) < 0);
+       }
+
+       @Test void a02_compareTo_greaterThan() {
+               var bm = bc.getBeanMeta(TestBean.class);
+               var pMeta1 = bm.getPropertyMeta("name");
+               var pMeta2 = bm.getPropertyMeta("age");
+
+               var pv1 = new BeanPropertyValue(pMeta1, "name", "John", null);
+               var pv2 = new BeanPropertyValue(pMeta2, "age", 25, null);
+
+               assertTrue(pv1.compareTo(pv2) > 0);
+       }
+
+       @Test void a03_compareTo_equal() {
+               var bm = bc.getBeanMeta(TestBean.class);
+               var pMeta = bm.getPropertyMeta("name");
+
+               var pv1 = new BeanPropertyValue(pMeta, "name", "John", null);
+               var pv2 = new BeanPropertyValue(pMeta, "name", "Jane", null);
+
+               assertEquals(0, pv1.compareTo(pv2));
+       }
+
+       
//====================================================================================================
+       // properties() and toString() - Lines 89-100 coverage
+       
//====================================================================================================
+
+       @Test void b01_properties() {
+               var bm = bc.getBeanMeta(TestBean.class);
+               var pMeta = bm.getPropertyMeta("name");
+               var pv = new BeanPropertyValue(pMeta, "name", "John", null);
+
+               var props = pv.properties();
+               assertEquals("name", props.get("name"));
+               assertEquals("John", props.get("value"));
+               assertNotNull(props.get("type"));
+       }
+
+       @Test void b02_toString() {
+               var bm = bc.getBeanMeta(TestBean.class);
+               var pMeta = bm.getPropertyMeta("name");
+               var pv = new BeanPropertyValue(pMeta, "name", "John", null);
+
+               var str = pv.toString();
+               assertNotNull(str);
+               assertTrue(str.contains("name"));
+               assertTrue(str.contains("John"));
+       }
+
+       @Test void b03_toString_withNullValue() {
+               var bm = bc.getBeanMeta(TestBean.class);
+               var pMeta = bm.getPropertyMeta("name");
+               var pv = new BeanPropertyValue(pMeta, "name", null, null);
+
+               var str = pv.toString();
+               assertNotNull(str);
+               assertTrue(str.contains("name"));
+       }
+}
+
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/BeanProxyInvocationHandler_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/BeanProxyInvocationHandler_Test.java
new file mode 100644
index 0000000000..85a2c0cd09
--- /dev/null
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/BeanProxyInvocationHandler_Test.java
@@ -0,0 +1,405 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.juneau;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.lang.reflect.*;
+
+import org.junit.jupiter.api.*;
+
+class BeanProxyInvocationHandler_Test extends TestBase {
+
+       public interface TestInterface {
+               String getName();
+               void setName(String name);
+               int getAge();
+               void setAge(int age);
+               boolean isActive();
+               void setActive(boolean active);
+       }
+
+       // Helper class with methods that have same names as Object methods but 
wrong signatures
+       // We can't put these in an interface because they conflict with Object 
methods
+       public static class HelperClassWithWrongSignatures {
+               public boolean equals(String other) { return false; }  // 
Wrong: should be equals(Object)
+               public int hashCode(int dummy) { return 0; }  // Wrong: should 
be hashCode()
+               public String toString(String format) { return ""; }  // Wrong: 
should be toString()
+       }
+
+       BeanContext bc = BeanContext.DEFAULT;
+
+       
//====================================================================================================
+       // Constructor
+       
//====================================================================================================
+
+       @Test void a01_constructor() {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               assertNotNull(handler);
+       }
+
+       
//====================================================================================================
+       // invoke() - equals() method
+       
//====================================================================================================
+
+       @Test void b01_equals_null() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               var method = Object.class.getMethod("equals", Object.class);
+               var result = handler.invoke(proxy, method, new Object[]{null});
+               assertFalse((Boolean)result);
+       }
+
+       @Test void b02_equals_sameProxy() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               var method = Object.class.getMethod("equals", Object.class);
+               var result = handler.invoke(proxy, method, new Object[]{proxy});
+               assertTrue((Boolean)result);
+       }
+
+       @Test void b03_equals_sameClassDifferentHandler() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler1 = new BeanProxyInvocationHandler<>(bm);
+               var handler2 = new BeanProxyInvocationHandler<>(bm);
+               var proxy1 = createProxy(TestInterface.class, handler1);
+               var proxy2 = createProxy(TestInterface.class, handler2);
+
+               // Set same values
+               proxy1.setName("John");
+               proxy1.setAge(25);
+               proxy2.setName("John");
+               proxy2.setAge(25);
+
+               var method = Object.class.getMethod("equals", Object.class);
+               var result = handler1.invoke(proxy1, method, new 
Object[]{proxy2});
+               assertTrue((Boolean)result);
+       }
+
+       @Test void b04_equals_differentValues() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler1 = new BeanProxyInvocationHandler<>(bm);
+               var handler2 = new BeanProxyInvocationHandler<>(bm);
+               var proxy1 = createProxy(TestInterface.class, handler1);
+               var proxy2 = createProxy(TestInterface.class, handler2);
+
+               // Set different values
+               proxy1.setName("John");
+               proxy1.setAge(25);
+               proxy2.setName("Jane");
+               proxy2.setAge(30);
+
+               var method = Object.class.getMethod("equals", Object.class);
+               var result = handler1.invoke(proxy1, method, new 
Object[]{proxy2});
+               assertFalse((Boolean)result);
+       }
+
+       @Test void b05_equals_withBeanMap() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               proxy.setName("John");
+               proxy.setAge(25);
+
+               // Create a regular bean with same values
+               var bean = new TestBean();
+               bean.name = "John";
+               bean.age = 25;
+
+               var method = Object.class.getMethod("equals", Object.class);
+               var result = handler.invoke(proxy, method, new Object[]{bean});
+               assertTrue((Boolean)result);
+       }
+
+       public static class TestBean {
+               public String name;
+               public int age;
+       }
+
+       
//====================================================================================================
+       // invoke() - hashCode() method
+       
//====================================================================================================
+
+       @Test void c01_hashCode() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               proxy.setName("John");
+               proxy.setAge(25);
+
+               var method = Object.class.getMethod("hashCode");
+               var result = handler.invoke(proxy, method, null);
+               assertNotNull(result);
+               assertTrue(result instanceof Integer);
+       }
+
+       @Test void c02_hashCode_sameValues() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler1 = new BeanProxyInvocationHandler<>(bm);
+               var handler2 = new BeanProxyInvocationHandler<>(bm);
+               var proxy1 = createProxy(TestInterface.class, handler1);
+               var proxy2 = createProxy(TestInterface.class, handler2);
+
+               proxy1.setName("John");
+               proxy1.setAge(25);
+               proxy2.setName("John");
+               proxy2.setAge(25);
+
+               var method = Object.class.getMethod("hashCode");
+               var hashCode1 = handler1.invoke(proxy1, method, null);
+               var hashCode2 = handler2.invoke(proxy2, method, null);
+               assertEquals(hashCode1, hashCode2);
+       }
+
+       
//====================================================================================================
+       // invoke() - toString() method
+       
//====================================================================================================
+
+       @Test void d01_toString() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               proxy.setName("John");
+               proxy.setAge(25);
+               proxy.setActive(true);
+
+               var method = Object.class.getMethod("toString");
+               var result = handler.invoke(proxy, method, null);
+               assertNotNull(result);
+               assertTrue(result instanceof String);
+               var str = (String)result;
+               assertTrue(str.contains("John") || str.contains("25") || 
str.contains("true"));
+       }
+
+       @Test void d02_toString_empty() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               var method = Object.class.getMethod("toString");
+               var result = handler.invoke(proxy, method, null);
+               assertNotNull(result);
+               assertTrue(result instanceof String);
+       }
+
+       
//====================================================================================================
+       // invoke() - getter methods
+       
//====================================================================================================
+
+       @Test void e01_getter_string() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               proxy.setName("John");
+
+               var method = TestInterface.class.getMethod("getName");
+               var result = handler.invoke(proxy, method, null);
+               assertEquals("John", result);
+       }
+
+       @Test void e02_getter_int() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               proxy.setAge(25);
+
+               var method = TestInterface.class.getMethod("getAge");
+               var result = handler.invoke(proxy, method, null);
+               assertEquals(25, result);
+       }
+
+       @Test void e03_getter_boolean() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               proxy.setActive(true);
+
+               var method = TestInterface.class.getMethod("isActive");
+               var result = handler.invoke(proxy, method, null);
+               assertEquals(true, result);
+       }
+
+       @Test void e04_getter_null() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               // Don't set name, should return null
+               var method = TestInterface.class.getMethod("getName");
+               var result = handler.invoke(proxy, method, null);
+               assertNull(result);
+       }
+
+       
//====================================================================================================
+       // invoke() - setter methods
+       
//====================================================================================================
+
+       @Test void f01_setter_string() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               var method = TestInterface.class.getMethod("setName", 
String.class);
+               var result = handler.invoke(proxy, method, new 
Object[]{"John"});
+               assertNull(result);
+
+               // Verify value was set
+               assertEquals("John", proxy.getName());
+       }
+
+       @Test void f02_setter_int() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               var method = TestInterface.class.getMethod("setAge", int.class);
+               var result = handler.invoke(proxy, method, new Object[]{25});
+               assertNull(result);
+
+               // Verify value was set
+               assertEquals(25, proxy.getAge());
+       }
+
+       @Test void f03_setter_boolean() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               var method = TestInterface.class.getMethod("setActive", 
boolean.class);
+               var result = handler.invoke(proxy, method, new Object[]{true});
+               assertNull(result);
+
+               // Verify value was set
+               assertTrue(proxy.isActive());
+       }
+
+       @Test void f04_setter_null() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               var method = TestInterface.class.getMethod("setName", 
String.class);
+               var result = handler.invoke(proxy, method, new Object[]{null});
+               assertNull(result);
+
+               // Verify null was set
+               assertNull(proxy.getName());
+       }
+
+       
//====================================================================================================
+       // invoke() - unsupported method
+       
//====================================================================================================
+
+       @Test void g01_unsupportedMethod() throws Exception {
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               // Create a method that's not a getter, setter, equals, 
hashCode, or toString
+               var method = Object.class.getMethod("getClass");
+               var exception = 
assertThrows(UnsupportedOperationException.class, () -> {
+                       handler.invoke(proxy, method, null);
+               });
+               assertNotNull(exception.getMessage());
+               assertTrue(exception.getMessage().contains("Unsupported bean 
method"));
+       }
+
+       
//====================================================================================================
+       // invoke() - methods with same name but wrong signatures (lines 59, 
74, 77 coverage)
+       
//====================================================================================================
+
+       @Test void h01_equals_wrongSignature() throws Exception {
+               // Test equals(String) - should not match the equals(Object) 
check on line 59
+               // Get the method from a helper class since we can't put it in 
an interface
+               var method = 
HelperClassWithWrongSignatures.class.getMethod("equals", String.class);
+
+               // Create handler with TestInterface (any interface will do for 
testing)
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               // This should fall through to getter/setter/unsupported logic 
since it doesn't match line 59
+               // (has name "equals" but wrong parameter type - String instead 
of Object)
+               var exception = 
assertThrows(UnsupportedOperationException.class, () -> {
+                       handler.invoke(proxy, method, new Object[]{"test"});
+               });
+               assertNotNull(exception.getMessage());
+               assertTrue(exception.getMessage().contains("Unsupported bean 
method"));
+       }
+
+       @Test void h02_hashCode_wrongSignature() throws Exception {
+               // Test hashCode(int) - should not match the hashCode() check 
on line 74
+               // Get the method from a helper class since we can't put it in 
an interface
+               var method = 
HelperClassWithWrongSignatures.class.getMethod("hashCode", int.class);
+
+               // Create handler with TestInterface (any interface will do for 
testing)
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               // This should fall through to getter/setter/unsupported logic 
since it doesn't match line 74
+               // (has name "hashCode" but wrong parameter count - 1 instead 
of 0)
+               var exception = 
assertThrows(UnsupportedOperationException.class, () -> {
+                       handler.invoke(proxy, method, new Object[]{42});
+               });
+               assertNotNull(exception.getMessage());
+               assertTrue(exception.getMessage().contains("Unsupported bean 
method"));
+       }
+
+       @Test void h03_toString_wrongSignature() throws Exception {
+               // Test toString(String) - should not match the toString() 
check on line 77
+               // Get the method from a helper class since we can't put it in 
an interface
+               var method = 
HelperClassWithWrongSignatures.class.getMethod("toString", String.class);
+
+               // Create handler with TestInterface (any interface will do for 
testing)
+               var bm = bc.getBeanMeta(TestInterface.class);
+               var handler = new BeanProxyInvocationHandler<>(bm);
+               var proxy = createProxy(TestInterface.class, handler);
+
+               // This should fall through to getter/setter/unsupported logic 
since it doesn't match line 77
+               // (has name "toString" but wrong parameter count - 1 instead 
of 0)
+               var exception = 
assertThrows(UnsupportedOperationException.class, () -> {
+                       handler.invoke(proxy, method, new Object[]{"format"});
+               });
+               assertNotNull(exception.getMessage());
+               assertTrue(exception.getMessage().contains("Unsupported bean 
method"));
+       }
+
+       
//====================================================================================================
+       // Helper methods
+       
//====================================================================================================
+
+       private static <T> T createProxy(Class<T> interfaceClass, 
InvocationHandler handler) {
+               return (T)Proxy.newProxyInstance(
+                       interfaceClass.getClassLoader(),
+                       new Class[]{interfaceClass},
+                       handler
+               );
+       }
+}
+
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/annotation/BeanConfigAnnotation_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/annotation/BeanConfigAnnotation_Test.java
index 0e26305ab6..aca26665f4 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/annotation/BeanConfigAnnotation_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/annotation/BeanConfigAnnotation_Test.java
@@ -42,7 +42,7 @@ class BeanConfigAnnotation_Test extends TestBase {
                assertEquals(expected, TO_STRING.apply(o));
        }
 
-       private static final Function<Object,String> TO_STRING = new 
Function<>() {
+               private static final Function<Object,String> TO_STRING = new 
Function<>() {
                @Override
                public String apply(Object t) {
                        if (t == null)
@@ -52,6 +52,11 @@ class BeanConfigAnnotation_Test extends TestBase {
                                        .stream()
                                        .map(TO_STRING)
                                        .collect(Collectors.joining(","));
+                       if (t instanceof Set)
+                               return ((Set<?>)t)
+                                       .stream()
+                                       .map(TO_STRING)
+                                       .collect(Collectors.joining(","));
                        if (isArray(t))
                                return apply(toList(t, Object.class));
                        if (t instanceof JsonMap)
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/commons/collections/MultiSet_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/MultiSet_Test.java
index aed9307575..ecc2c51e9b 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/commons/collections/MultiSet_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/MultiSet_Test.java
@@ -320,13 +320,14 @@ class MultiSet_Test extends TestBase {
                assertFalse(it.hasNext()); // i2 is null, should return false
        }
 
+       @SuppressWarnings("unlikely-arg-type")
        @Test
        void equals_notASet_otherTypes() {
                // Line 308: return (o instanceof Set o2) && ...
                // Test when object is not a Set (testing the instanceof check)
                var l1 = l(a("1", "2"));
                var multiSet = new MultiSet<>(l1);
-               
+
                // Not a Set - should return false immediately due to 
instanceof check
                assertFalse(multiSet.equals("not a set"));
                assertFalse(multiSet.equals(123));
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/AssertionUtils_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/AssertionUtils_Test.java
index 75bdd20e88..3e96125121 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/AssertionUtils_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/AssertionUtils_Test.java
@@ -392,39 +392,39 @@ class AssertionUtils_Test extends TestBase {
        void a012_assertVarargsNotNull() {
                // Should not throw when array and elements are not null
                var array = a("a", "b", "c");
-               var result = assertVarargsNotNull("arg", array);
+               var result = assertArgNoNulls("arg", array);
                assertSame(array, result);
                
                // Should not throw with empty array
                var emptyArray = new String[0];
-               var result2 = assertVarargsNotNull("arg", emptyArray);
+               var result2 = assertArgNoNulls("arg", emptyArray);
                assertSame(emptyArray, result2);
                
                // Should work with integer array
                var intArray = a(1, 2, 3);
-               var result3 = assertVarargsNotNull("arg", intArray);
+               var result3 = assertArgNoNulls("arg", intArray);
                assertSame(intArray, result3);
                
                // Should work with object array
                var objArray = a(new Object(), new Object());
-               var result4 = assertVarargsNotNull("arg", objArray);
+               var result4 = assertArgNoNulls("arg", objArray);
                assertSame(objArray, result4);
                
                // Should throw when array is null
                assertThrowsWithMessage(IllegalArgumentException.class, 
l("arg", "cannot be null"), () -> {
-                       assertVarargsNotNull("arg", (String[])null);
+                       assertArgNoNulls("arg", (String[])null);
                });
                
                // Should throw when element is null
                var nullElementArray = a("a", null, "c");
                assertThrowsWithMessage(IllegalArgumentException.class, 
l("arg", "parameter", "1"), () -> {
-                       assertVarargsNotNull("arg", nullElementArray);
+                       assertArgNoNulls("arg", nullElementArray);
                });
                
                // Should fail on first null when multiple elements are null
                var multipleNullArray = a("a", null, null, "d");
                assertThrowsWithMessage(IllegalArgumentException.class, "1", () 
-> {
-                       assertVarargsNotNull("arg", multipleNullArray);
+                       assertArgNoNulls("arg", multipleNullArray);
                });
        }
 }

Reply via email to