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 959b73835a Marshall module improvements
959b73835a is described below

commit 959b73835a95c71668b7f1fe18cd09330ce9d27f
Author: James Bognar <[email protected]>
AuthorDate: Sat Dec 13 08:37:56 2025 -0500

    Marshall module improvements
---
 .../juneau/commons/collections/FilteredMap.java    |   2 -
 .../juneau/commons/collections/FluentList.java     | 287 +++++++++++++
 .../juneau/commons/collections/FluentMap.java      | 235 +++++++++++
 .../juneau/commons/collections/FluentSet.java      | 241 +++++++++++
 .../juneau/commons/collections/MapBuilder.java     |  21 +
 .../juneau/commons/utils/CollectionUtils.java      |  11 +
 .../commons/collections/FluentList_Test.java       | 464 +++++++++++++++++++++
 .../juneau/commons/collections/FluentMap_Test.java | 441 ++++++++++++++++++++
 .../juneau/commons/collections/FluentSet_Test.java | 416 ++++++++++++++++++
 9 files changed, 2116 insertions(+), 2 deletions(-)

diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredMap.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredMap.java
index 2e2abbeefa..0d55c27cb0 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredMap.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredMap.java
@@ -555,7 +555,6 @@ public class FilteredMap<K,V> extends AbstractMap<K,V> {
                }
        }
 
-       @SuppressWarnings("unchecked")
        private K convertKey(Object key) {
                if (keyFunction != null) {
                        key = keyFunction.apply(key);
@@ -571,7 +570,6 @@ public class FilteredMap<K,V> extends AbstractMap<K,V> {
                throw rex("Object of type {0} could not be converted to key 
type {1}", cn(key), cn(keyType));
        }
 
-       @SuppressWarnings("unchecked")
        private V convertValue(Object value) {
                if (valueFunction != null) {
                        value = valueFunction.apply(value);
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FluentList.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FluentList.java
new file mode 100644
index 0000000000..a286922e82
--- /dev/null
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FluentList.java
@@ -0,0 +1,287 @@
+/*
+ * 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.commons.collections;
+
+import static org.apache.juneau.commons.utils.AssertionUtils.*;
+
+import java.util.*;
+
+/**
+ * A fluent wrapper around an arbitrary list that provides convenient methods 
for adding elements.
+ *
+ * <p>
+ * This class wraps an underlying list and provides a fluent API for adding 
elements. All methods return
+ * <c>this</c> to allow method chaining. The underlying list can be any {@link 
List} implementation.
+ *
+ * <h5 class='section'>Features:</h5>
+ * <ul class='spaced-list'>
+ *     <li><b>Fluent API:</b> All methods return <c>this</c> for method 
chaining
+ *     <li><b>Arbitrary List Support:</b> Works with any list implementation
+ *     <li><b>Conditional Adding:</b> Add elements conditionally based on 
boolean expressions
+ *     <li><b>Transparent Interface:</b> Implements the full {@link List} 
interface, so it can be used anywhere a list is expected
+ * </ul>
+ *
+ * <h5 class='section'>Usage:</h5>
+ * <p class='bjava'>
+ *     <jc>// Create a FluentList wrapping an ArrayList</jc>
+ *     FluentList&lt;String&gt; <jv>list</jv> = <jk>new</jk> 
FluentList&lt;&gt;(<jk>new</jk> ArrayList&lt;&gt;());
+ *
+ *     <jv>list</jv>
+ *             .a(<js>"item1"</js>)
+ *             .a(<js>"item2"</js>)
+ *             .ai(<jk>true</jk>, <js>"item3"</js>)   <jc>// Added</jc>
+ *             .ai(<jk>false</jk>, <js>"item4"</js>); <jc>// Not added</jc>
+ *
+ *     <jc>// Add all elements from another collection</jc>
+ *     List&lt;String&gt; <jv>other</jv> = List.of(<js>"item5"</js>, 
<js>"item6"</js>);
+ *     <jv>list</jv>.aa(<jv>other</jv>);
+ * </p>
+ *
+ * <h5 class='section'>Example - Conditional Building:</h5>
+ * <p class='bjava'>
+ *     <jk>boolean</jk> <jv>includeDebug</jv> = <jk>true</jk>;
+ *     <jk>boolean</jk> <jv>includeTest</jv> = <jk>false</jk>;
+ *
+ *     FluentList&lt;String&gt; <jv>config</jv> = <jk>new</jk> 
FluentList&lt;&gt;(<jk>new</jk> ArrayList&lt;&gt;())
+ *             .a(<js>"setting1"</js>)
+ *             .a(<js>"setting2"</js>)
+ *             .ai(<jv>includeDebug</jv>, <js>"debug"</js>)   <jc>// Added</jc>
+ *             .ai(<jv>includeTest</jv>, <js>"test"</js>);    <jc>// Not 
added</jc>
+ * </p>
+ *
+ * <h5 class='section'>Behavior Notes:</h5>
+ * <ul class='spaced-list'>
+ *     <li>All list operations are delegated to the underlying list
+ *     <li>The fluent methods ({@link #a(Object)}, {@link #aa(Collection)}, 
{@link #ai(boolean, Object)}) return <c>this</c> for chaining
+ *     <li>If a <jk>null</jk> collection is passed to {@link #a(Collection)}, 
it is treated as a no-op
+ *     <li>The underlying list is stored by reference (not copied), so 
modifications affect the original list
+ * </ul>
+ *
+ * <h5 class='section'>Thread Safety:</h5>
+ * <p>
+ * This class is not thread-safe unless the underlying list is thread-safe. If 
thread safety is required,
+ * use a thread-safe list type (e.g., {@link 
java.util.concurrent.CopyOnWriteArrayList}).
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ *     <li class='link'><a class="doclink" 
href="../../../../../index.html#juneau-commons">Overview &gt; juneau-commons</a>
+ * </ul>
+ *
+ * @param <E> The element type.
+ */
+public class FluentList<E> extends AbstractList<E> {
+
+       private final List<E> list;
+
+       /**
+        * Constructor.
+        *
+        * @param inner The underlying list to wrap. Must not be <jk>null</jk>.
+        */
+       public FluentList(List<E> inner) {
+               this.list = assertArgNotNull("inner", inner);
+       }
+
+       /**
+        * Adds a single element to this list.
+        *
+        * <p>
+        * This is a convenience method that calls {@link #add(Object)} and 
returns <c>this</c>
+        * for method chaining.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      FluentList&lt;String&gt; <jv>list</jv> = <jk>new</jk> 
FluentList&lt;&gt;(<jk>new</jk> ArrayList&lt;&gt;());
+        *      <jv>list</jv>.a(<js>"item1"</js>).a(<js>"item2"</js>);
+        * </p>
+        *
+        * @param element The element to add.
+        * @return This object for method chaining.
+        */
+       public FluentList<E> a(E element) {
+               list.add(element);
+               return this;
+       }
+
+       /**
+        * Adds all elements from the specified collection to this list.
+        *
+        * <p>
+        * This is a convenience method that calls {@link #addAll(Collection)} 
and returns <c>this</c>
+        * for method chaining. If the specified collection is <jk>null</jk>, 
this is a no-op.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      FluentList&lt;String&gt; <jv>list</jv> = <jk>new</jk> 
FluentList&lt;&gt;(<jk>new</jk> ArrayList&lt;&gt;());
+        *      List&lt;String&gt; <jv>other</jv> = List.of(<js>"item1"</js>, 
<js>"item2"</js>);
+        *      <jv>list</jv>.aa(<jv>other</jv>).a(<js>"item3"</js>);
+        * </p>
+        *
+        * @param c The collection whose elements are to be added. Can be 
<jk>null</jk> (no-op).
+        * @return This object for method chaining.
+        */
+       public FluentList<E> aa(Collection<? extends E> c) {
+               if (c != null)
+                       list.addAll(c);
+               return this;
+       }
+
+       /**
+        * Adds an element to this list if the specified boolean condition is 
<jk>true</jk>.
+        *
+        * <p>
+        * This method is useful for conditionally adding elements based on 
runtime conditions.
+        * If the condition is <jk>false</jk>, the element is not added and 
this method returns <c>this</c>
+        * without modifying the list.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      <jk>boolean</jk> <jv>includeDebug</jv> = <jk>true</jk>;
+        *      <jk>boolean</jk> <jv>includeTest</jv> = <jk>false</jk>;
+        *
+        *      FluentList&lt;String&gt; <jv>list</jv> = <jk>new</jk> 
FluentList&lt;&gt;(<jk>new</jk> ArrayList&lt;&gt;())
+        *              .a(<js>"basic"</js>)
+        *              .ai(<jv>includeDebug</jv>, <js>"debug"</js>)   <jc>// 
Added</jc>
+        *              .ai(<jv>includeTest</jv>, <js>"test"</js>);    <jc>// 
Not added</jc>
+        * </p>
+        *
+        * @param condition The condition to evaluate. If <jk>true</jk>, the 
element is added; if <jk>false</jk>, it is not.
+        * @param element The element to add if the condition is <jk>true</jk>.
+        * @return This object for method chaining.
+        */
+       public FluentList<E> ai(boolean condition, E element) {
+               if (condition)
+                       list.add(element);
+               return this;
+       }
+
+       @Override
+       public E get(int index) {
+               return list.get(index);
+       }
+
+       @Override
+       public int size() {
+               return list.size();
+       }
+
+       @Override
+       public boolean add(E e) {
+               return list.add(e);
+       }
+
+       @Override
+       public void add(int index, E element) {
+               list.add(index, element);
+       }
+
+       @Override
+       public boolean addAll(Collection<? extends E> c) {
+               return list.addAll(c);
+       }
+
+       @Override
+       public boolean addAll(int index, Collection<? extends E> c) {
+               return list.addAll(index, c);
+       }
+
+       @Override
+       public E remove(int index) {
+               return list.remove(index);
+       }
+
+       @Override
+       public boolean remove(Object o) {
+               return list.remove(o);
+       }
+
+       @Override
+       public boolean removeAll(Collection<?> c) {
+               return list.removeAll(c);
+       }
+
+       @Override
+       public boolean retainAll(Collection<?> c) {
+               return list.retainAll(c);
+       }
+
+       @Override
+       public void clear() {
+               list.clear();
+       }
+
+       @Override
+       public E set(int index, E element) {
+               return list.set(index, element);
+       }
+
+       @Override
+       public int indexOf(Object o) {
+               return list.indexOf(o);
+       }
+
+       @Override
+       public int lastIndexOf(Object o) {
+               return list.lastIndexOf(o);
+       }
+
+       @Override
+       public ListIterator<E> listIterator() {
+               return list.listIterator();
+       }
+
+       @Override
+       public ListIterator<E> listIterator(int index) {
+               return list.listIterator(index);
+       }
+
+       @Override
+       public List<E> subList(int fromIndex, int toIndex) {
+               return list.subList(fromIndex, toIndex);
+       }
+
+       @Override
+       public boolean contains(Object o) {
+               return list.contains(o);
+       }
+
+       @Override
+       public boolean containsAll(Collection<?> c) {
+               return list.containsAll(c);
+       }
+
+       @Override
+       public boolean isEmpty() {
+               return list.isEmpty();
+       }
+
+       @Override
+       public Iterator<E> iterator() {
+               return list.iterator();
+       }
+
+       @Override
+       public Object[] toArray() {
+               return list.toArray();
+       }
+
+       @Override
+       public <T> T[] toArray(T[] a) {
+               return list.toArray(a);
+       }
+}
+
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FluentMap.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FluentMap.java
new file mode 100644
index 0000000000..4f69a20f28
--- /dev/null
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FluentMap.java
@@ -0,0 +1,235 @@
+/*
+ * 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.commons.collections;
+
+import static org.apache.juneau.commons.utils.AssertionUtils.*;
+
+import java.util.*;
+
+/**
+ * A fluent wrapper around an arbitrary map that provides convenient methods 
for adding entries.
+ *
+ * <p>
+ * This class wraps an underlying map and provides a fluent API for adding 
entries. All methods return
+ * <c>this</c> to allow method chaining. The underlying map can be any {@link 
Map} implementation.
+ *
+ * <h5 class='section'>Features:</h5>
+ * <ul class='spaced-list'>
+ *     <li><b>Fluent API:</b> All methods return <c>this</c> for method 
chaining
+ *     <li><b>Arbitrary Map Support:</b> Works with any map implementation
+ *     <li><b>Conditional Adding:</b> Add entries conditionally based on 
boolean expressions
+ *     <li><b>Transparent Interface:</b> Implements the full {@link Map} 
interface, so it can be used anywhere a map is expected
+ * </ul>
+ *
+ * <h5 class='section'>Usage:</h5>
+ * <p class='bjava'>
+ *     <jc>// Create a FluentMap wrapping a LinkedHashMap</jc>
+ *     FluentMap&lt;String, String&gt; <jv>map</jv> = <jk>new</jk> 
FluentMap&lt;&gt;(<jk>new</jk> LinkedHashMap&lt;&gt;());
+ *
+ *     <jv>map</jv>
+ *             .a(<js>"key1"</js>, <js>"value1"</js>)
+ *             .a(<js>"key2"</js>, <js>"value2"</js>)
+ *             .ai(<jk>true</jk>, <js>"key3"</js>, <js>"value3"</js>)   <jc>// 
Added</jc>
+ *             .ai(<jk>false</jk>, <js>"key4"</js>, <js>"value4"</js>); <jc>// 
Not added</jc>
+ *
+ *     <jc>// Add all entries from another map</jc>
+ *     Map&lt;String, String&gt; <jv>other</jv> = Map.of(<js>"key5"</js>, 
<js>"value5"</js>, <js>"key6"</js>, <js>"value6"</js>);
+ *     <jv>map</jv>.aa(<jv>other</jv>);
+ * </p>
+ *
+ * <h5 class='section'>Example - Conditional Building:</h5>
+ * <p class='bjava'>
+ *     <jk>boolean</jk> <jv>includeDebug</jv> = <jk>true</jk>;
+ *     <jk>boolean</jk> <jv>includeTest</jv> = <jk>false</jk>;
+ *
+ *     FluentMap&lt;String, String&gt; <jv>config</jv> = <jk>new</jk> 
FluentMap&lt;&gt;(<jk>new</jk> LinkedHashMap&lt;&gt;())
+ *             .a(<js>"host"</js>, <js>"localhost"</js>)
+ *             .a(<js>"port"</js>, <js>"8080"</js>)
+ *             .ai(<jv>includeDebug</jv>, <js>"debug"</js>, <js>"true"</js>)   
<jc>// Added</jc>
+ *             .ai(<jv>includeTest</jv>, <js>"test"</js>, <js>"true"</js>);    
<jc>// Not added</jc>
+ * </p>
+ *
+ * <h5 class='section'>Behavior Notes:</h5>
+ * <ul class='spaced-list'>
+ *     <li>All map operations are delegated to the underlying map
+ *     <li>The fluent methods ({@link #a(Object, Object)}, {@link #aa(Map)}, 
{@link #ai(boolean, Object, Object)}) return <c>this</c> for chaining
+ *     <li>If a <jk>null</jk> map is passed to {@link #a(Map)}, it is treated 
as a no-op
+ *     <li>The underlying map is stored by reference (not copied), so 
modifications affect the original map
+ * </ul>
+ *
+ * <h5 class='section'>Thread Safety:</h5>
+ * <p>
+ * This class is not thread-safe unless the underlying map is thread-safe. If 
thread safety is required,
+ * use a thread-safe map type (e.g., {@link 
java.util.concurrent.ConcurrentHashMap}).
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ *     <li class='link'><a class="doclink" 
href="../../../../../index.html#juneau-commons">Overview &gt; juneau-commons</a>
+ * </ul>
+ *
+ * @param <K> The key type.
+ * @param <V> The value type.
+ */
+public class FluentMap<K,V> extends AbstractMap<K,V> {
+
+       private final Map<K,V> map;
+
+       /**
+        * Constructor.
+        *
+        * @param inner The underlying map to wrap. Must not be <jk>null</jk>.
+        */
+       public FluentMap(Map<K,V> inner) {
+               this.map = assertArgNotNull("inner", inner);
+       }
+
+       /**
+        * Adds a single key-value pair to this map.
+        *
+        * <p>
+        * This is a convenience method that calls {@link #put(Object, Object)} 
and returns <c>this</c>
+        * for method chaining.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      FluentMap&lt;String, String&gt; <jv>map</jv> = <jk>new</jk> 
FluentMap&lt;&gt;(<jk>new</jk> LinkedHashMap&lt;&gt;());
+        *      <jv>map</jv>.a(<js>"key1"</js>, 
<js>"value1"</js>).a(<js>"key2"</js>, <js>"value2"</js>);
+        * </p>
+        *
+        * @param key The key to add.
+        * @param value The value to add.
+        * @return This object for method chaining.
+        */
+       public FluentMap<K,V> a(K key, V value) {
+               map.put(key, value);
+               return this;
+       }
+
+       /**
+        * Adds all entries from the specified map to this map.
+        *
+        * <p>
+        * This is a convenience method that calls {@link #putAll(Map)} and 
returns <c>this</c>
+        * for method chaining. If the specified map is <jk>null</jk>, this is 
a no-op.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      FluentMap&lt;String, String&gt; <jv>map</jv> = <jk>new</jk> 
FluentMap&lt;&gt;(<jk>new</jk> LinkedHashMap&lt;&gt;());
+        *      Map&lt;String, String&gt; <jv>other</jv> = 
Map.of(<js>"key1"</js>, <js>"value1"</js>, <js>"key2"</js>, <js>"value2"</js>);
+        *      <jv>map</jv>.aa(<jv>other</jv>).a(<js>"key3"</js>, 
<js>"value3"</js>);
+        * </p>
+        *
+        * @param m The map whose entries are to be added. Can be <jk>null</jk> 
(no-op).
+        * @return This object for method chaining.
+        */
+       public FluentMap<K,V> aa(Map<? extends K, ? extends V> m) {
+               if (m != null)
+                       map.putAll(m);
+               return this;
+       }
+
+       /**
+        * Adds a key-value pair to this map if the specified boolean condition 
is <jk>true</jk>.
+        *
+        * <p>
+        * This method is useful for conditionally adding entries based on 
runtime conditions.
+        * If the condition is <jk>false</jk>, the entry is not added and this 
method returns <c>this</c>
+        * without modifying the map.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      <jk>boolean</jk> <jv>includeDebug</jv> = <jk>true</jk>;
+        *      <jk>boolean</jk> <jv>includeTest</jv> = <jk>false</jk>;
+        *
+        *      FluentMap&lt;String, String&gt; <jv>map</jv> = <jk>new</jk> 
FluentMap&lt;&gt;(<jk>new</jk> LinkedHashMap&lt;&gt;())
+        *              .a(<js>"host"</js>, <js>"localhost"</js>)
+        *              .ai(<jv>includeDebug</jv>, <js>"debug"</js>, 
<js>"true"</js>)   <jc>// Added</jc>
+        *              .ai(<jv>includeTest</jv>, <js>"test"</js>, 
<js>"true"</js>);    <jc>// Not added</jc>
+        * </p>
+        *
+        * @param condition The condition to evaluate. If <jk>true</jk>, the 
entry is added; if <jk>false</jk>, it is not.
+        * @param key The key to add if the condition is <jk>true</jk>.
+        * @param value The value to add if the condition is <jk>true</jk>.
+        * @return This object for method chaining.
+        */
+       public FluentMap<K,V> ai(boolean condition, K key, V value) {
+               if (condition)
+                       map.put(key, value);
+               return this;
+       }
+
+       @Override
+       public Set<Entry<K,V>> entrySet() {
+               return map.entrySet();
+       }
+
+       @Override
+       public V get(Object key) {
+               return map.get(key);
+       }
+
+       @Override
+       public V put(K key, V value) {
+               return map.put(key, value);
+       }
+
+       @Override
+       public V remove(Object key) {
+               return map.remove(key);
+       }
+
+       @Override
+       public void putAll(Map<? extends K, ? extends V> m) {
+               map.putAll(m);
+       }
+
+       @Override
+       public void clear() {
+               map.clear();
+       }
+
+       @Override
+       public boolean containsKey(Object key) {
+               return map.containsKey(key);
+       }
+
+       @Override
+       public boolean containsValue(Object value) {
+               return map.containsValue(value);
+       }
+
+       @Override
+       public int size() {
+               return map.size();
+       }
+
+       @Override
+       public boolean isEmpty() {
+               return map.isEmpty();
+       }
+
+       @Override
+       public Set<K> keySet() {
+               return map.keySet();
+       }
+
+       @Override
+       public Collection<V> values() {
+               return map.values();
+       }
+}
+
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FluentSet.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FluentSet.java
new file mode 100644
index 0000000000..5fc6a6de74
--- /dev/null
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FluentSet.java
@@ -0,0 +1,241 @@
+/*
+ * 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.commons.collections;
+
+import static org.apache.juneau.commons.utils.AssertionUtils.*;
+
+import java.util.*;
+
+/**
+ * A fluent wrapper around an arbitrary set that provides convenient methods 
for adding elements.
+ *
+ * <p>
+ * This class wraps an underlying set and provides a fluent API for adding 
elements. All methods return
+ * <c>this</c> to allow method chaining. The underlying set can be any {@link 
Set} implementation.
+ *
+ * <h5 class='section'>Features:</h5>
+ * <ul class='spaced-list'>
+ *     <li><b>Fluent API:</b> All methods return <c>this</c> for method 
chaining
+ *     <li><b>Arbitrary Set Support:</b> Works with any set implementation
+ *     <li><b>Conditional Adding:</b> Add elements conditionally based on 
boolean expressions
+ *     <li><b>Transparent Interface:</b> Implements the full {@link Set} 
interface, so it can be used anywhere a set is expected
+ *     <li><b>Automatic Deduplication:</b> Duplicate elements are 
automatically handled by the underlying set
+ * </ul>
+ *
+ * <h5 class='section'>Usage:</h5>
+ * <p class='bjava'>
+ *     <jc>// Create a FluentSet wrapping a LinkedHashSet</jc>
+ *     FluentSet&lt;String&gt; <jv>set</jv> = <jk>new</jk> 
FluentSet&lt;&gt;(<jk>new</jk> LinkedHashSet&lt;&gt;());
+ *
+ *     <jv>set</jv>
+ *             .a(<js>"item1"</js>)
+ *             .a(<js>"item2"</js>)
+ *             .ai(<jk>true</jk>, <js>"item3"</js>)   <jc>// Added</jc>
+ *             .ai(<jk>false</jk>, <js>"item4"</js>); <jc>// Not added</jc>
+ *
+ *     <jc>// Add all elements from another collection</jc>
+ *     Set&lt;String&gt; <jv>other</jv> = Set.of(<js>"item5"</js>, 
<js>"item6"</js>);
+ *     <jv>set</jv>.aa(<jv>other</jv>);
+ * </p>
+ *
+ * <h5 class='section'>Example - Conditional Building:</h5>
+ * <p class='bjava'>
+ *     <jk>boolean</jk> <jv>includeDebug</jv> = <jk>true</jk>;
+ *     <jk>boolean</jk> <jv>includeTest</jv> = <jk>false</jk>;
+ *
+ *     FluentSet&lt;String&gt; <jv>set</jv> = <jk>new</jk> 
FluentSet&lt;&gt;(<jk>new</jk> LinkedHashSet&lt;&gt;())
+ *             .a(<js>"setting1"</js>)
+ *             .a(<js>"setting2"</js>)
+ *             .ai(<jv>includeDebug</jv>, <js>"debug"</js>)   <jc>// Added</jc>
+ *             .ai(<jv>includeTest</jv>, <js>"test"</js>);    <jc>// Not 
added</jc>
+ * </p>
+ *
+ * <h5 class='section'>Behavior Notes:</h5>
+ * <ul class='spaced-list'>
+ *     <li>All set operations are delegated to the underlying set
+ *     <li>The fluent methods ({@link #a(Object)}, {@link #aa(Collection)}, 
{@link #ai(boolean, Object)}) return <c>this</c> for chaining
+ *     <li>If a <jk>null</jk> collection is passed to {@link #a(Collection)}, 
it is treated as a no-op
+ *     <li>The underlying set is stored by reference (not copied), so 
modifications affect the original set
+ *     <li>Duplicate elements are automatically handled by the underlying set 
(only one occurrence is stored)
+ * </ul>
+ *
+ * <h5 class='section'>Thread Safety:</h5>
+ * <p>
+ * This class is not thread-safe unless the underlying set is thread-safe. If 
thread safety is required,
+ * use a thread-safe set type (e.g., {@link 
java.util.concurrent.CopyOnWriteArraySet}).
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ *     <li class='link'><a class="doclink" 
href="../../../../../index.html#juneau-commons">Overview &gt; juneau-commons</a>
+ * </ul>
+ *
+ * @param <E> The element type.
+ */
+public class FluentSet<E> extends AbstractSet<E> {
+
+       private final Set<E> set;
+
+       /**
+        * Constructor.
+        *
+        * @param inner The underlying set to wrap. Must not be <jk>null</jk>.
+        */
+       public FluentSet(Set<E> inner) {
+               this.set = assertArgNotNull("inner", inner);
+       }
+
+       /**
+        * Adds a single element to this set.
+        *
+        * <p>
+        * This is a convenience method that calls {@link #add(Object)} and 
returns <c>this</c>
+        * for method chaining. If the element already exists in the set, it is 
not added again
+        * (sets do not allow duplicates).
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      FluentSet&lt;String&gt; <jv>set</jv> = <jk>new</jk> 
FluentSet&lt;&gt;(<jk>new</jk> LinkedHashSet&lt;&gt;());
+        *      <jv>set</jv>.a(<js>"item1"</js>).a(<js>"item2"</js>);
+        * </p>
+        *
+        * @param element The element to add.
+        * @return This object for method chaining.
+        */
+       public FluentSet<E> a(E element) {
+               set.add(element);
+               return this;
+       }
+
+       /**
+        * Adds all elements from the specified collection to this set.
+        *
+        * <p>
+        * This is a convenience method that calls {@link #addAll(Collection)} 
and returns <c>this</c>
+        * for method chaining. If the specified collection is <jk>null</jk>, 
this is a no-op.
+        * Duplicate elements in the collection are automatically handled (only 
one occurrence is stored).
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      FluentSet&lt;String&gt; <jv>set</jv> = <jk>new</jk> 
FluentSet&lt;&gt;(<jk>new</jk> LinkedHashSet&lt;&gt;());
+        *      List&lt;String&gt; <jv>other</jv> = List.of(<js>"item1"</js>, 
<js>"item2"</js>);
+        *      <jv>set</jv>.aa(<jv>other</jv>).a(<js>"item3"</js>);
+        * </p>
+        *
+        * @param c The collection whose elements are to be added. Can be 
<jk>null</jk> (no-op).
+        * @return This object for method chaining.
+        */
+       public FluentSet<E> aa(Collection<? extends E> c) {
+               if (c != null)
+                       set.addAll(c);
+               return this;
+       }
+
+       /**
+        * Adds an element to this set if the specified boolean condition is 
<jk>true</jk>.
+        *
+        * <p>
+        * This method is useful for conditionally adding elements based on 
runtime conditions.
+        * If the condition is <jk>false</jk>, the element is not added and 
this method returns <c>this</c>
+        * without modifying the set.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      <jk>boolean</jk> <jv>includeDebug</jv> = <jk>true</jk>;
+        *      <jk>boolean</jk> <jv>includeTest</jv> = <jk>false</jk>;
+        *
+        *      FluentSet&lt;String&gt; <jv>set</jv> = <jk>new</jk> 
FluentSet&lt;&gt;(<jk>new</jk> LinkedHashSet&lt;&gt;())
+        *              .a(<js>"basic"</js>)
+        *              .ai(<jv>includeDebug</jv>, <js>"debug"</js>)   <jc>// 
Added</jc>
+        *              .ai(<jv>includeTest</jv>, <js>"test"</js>);    <jc>// 
Not added</jc>
+        * </p>
+        *
+        * @param condition The condition to evaluate. If <jk>true</jk>, the 
element is added; if <jk>false</jk>, it is not.
+        * @param element The element to add if the condition is <jk>true</jk>.
+        * @return This object for method chaining.
+        */
+       public FluentSet<E> ai(boolean condition, E element) {
+               if (condition)
+                       set.add(element);
+               return this;
+       }
+
+       @Override
+       public Iterator<E> iterator() {
+               return set.iterator();
+       }
+
+       @Override
+       public int size() {
+               return set.size();
+       }
+
+       @Override
+       public boolean add(E e) {
+               return set.add(e);
+       }
+
+       @Override
+       public boolean addAll(Collection<? extends E> c) {
+               return set.addAll(c);
+       }
+
+       @Override
+       public boolean remove(Object o) {
+               return set.remove(o);
+       }
+
+       @Override
+       public boolean removeAll(Collection<?> c) {
+               return set.removeAll(c);
+       }
+
+       @Override
+       public boolean retainAll(Collection<?> c) {
+               return set.retainAll(c);
+       }
+
+       @Override
+       public void clear() {
+               set.clear();
+       }
+
+       @Override
+       public boolean contains(Object o) {
+               return set.contains(o);
+       }
+
+       @Override
+       public boolean containsAll(Collection<?> c) {
+               return set.containsAll(c);
+       }
+
+       @Override
+       public boolean isEmpty() {
+               return set.isEmpty();
+       }
+
+       @Override
+       public Object[] toArray() {
+               return set.toArray();
+       }
+
+       @Override
+       public <T> T[] toArray(T[] a) {
+               return set.toArray(a);
+       }
+}
+
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/MapBuilder.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/MapBuilder.java
index dc098d4f95..0a63eca7b2 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/MapBuilder.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/MapBuilder.java
@@ -124,6 +124,27 @@ public class MapBuilder<K,V> {
                return new MapBuilder<>(assertArgNotNull("keyType", keyType), 
assertArgNotNull("valueType", valueType));
        }
 
+       /**
+        * Static creator without explicit type parameters.
+        *
+        * <p>
+        * This is a convenience method that creates a builder without 
requiring explicit type parameters.
+        * The types will be inferred from usage context. Internally uses 
<c>Object.class</c> for both
+        * key and value types, which allows any types to be added.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      Map&lt;String, Integer&gt; <jv>map</jv> = 
MapBuilder.<jsm>create</jsm>()
+        *              .add(<js>"one"</js>, 1)
+        *              .add(<js>"two"</js>, 2)
+        *              .build();
+        * </p>
+        *
+        * @param <K> Key type.
+        * @param <V> Value type.
+        * @return A new builder.
+        */
+       @SuppressWarnings({ "unchecked", "rawtypes" })
        public static <K,V> MapBuilder<K,V> create() {
                return new MapBuilder(Object.class, Object.class);
        }
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/CollectionUtils.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/CollectionUtils.java
index 3e30c4c13c..7103207f32 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/CollectionUtils.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/CollectionUtils.java
@@ -1584,6 +1584,17 @@ public class CollectionUtils {
                return Collections.emptyMap();
        }
 
+       /**
+        * Shortcut for creating an empty map with generic types.
+        *
+        * <p>
+        * This is a convenience method that creates an empty unmodifiable map 
without requiring
+        * explicit type parameters. The types will be inferred from usage 
context.
+        *
+        * @param <K> The key type.
+        * @param <V> The value type.
+        * @return An empty unmodifiable map.
+        */
        public static <K,V> Map<K,V> mape() {
                return Collections.emptyMap();
        }
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/commons/collections/FluentList_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/FluentList_Test.java
new file mode 100644
index 0000000000..5e89af5f08
--- /dev/null
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/FluentList_Test.java
@@ -0,0 +1,464 @@
+/*
+ * 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.commons.collections;
+
+import static org.apache.juneau.junit.bct.BctAssertions.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.junit.jupiter.api.*;
+
+class FluentList_Test extends TestBase {
+
+       
//====================================================================================================
+       // Basic functionality - a(E element)
+       
//====================================================================================================
+
+       @Test
+       void a01_addSingleElement() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item2").a("item3");
+
+               assertSize(3, list);
+               assertEquals("item1", list.get(0));
+               assertEquals("item2", list.get(1));
+               assertEquals("item3", list.get(2));
+       }
+
+       @Test
+       void a02_addSingleElement_returnsThis() {
+               var list = new FluentList<>(new ArrayList<String>());
+               var result = list.a("item1");
+
+               assertSame(list, result);
+       }
+
+       @Test
+       void a03_addSingleElement_nullValue() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a(null).a("item3");
+
+               assertSize(3, list);
+               assertEquals("item1", list.get(0));
+               assertNull(list.get(1));
+               assertEquals("item3", list.get(2));
+       }
+
+       
//====================================================================================================
+       // a(Collection) method
+       
//====================================================================================================
+
+       @Test
+       void b01_addCollection() {
+               var list = new FluentList<>(new ArrayList<String>());
+               var other = List.of("item1", "item2", "item3");
+               list.aa(other);
+
+               assertSize(3, list);
+               assertEquals("item1", list.get(0));
+               assertEquals("item2", list.get(1));
+               assertEquals("item3", list.get(2));
+       }
+
+       @Test
+       void b02_addCollection_returnsThis() {
+               var list = new FluentList<>(new ArrayList<String>());
+               var other = List.of("item1", "item2");
+               var result = list.aa(other);
+
+               assertSame(list, result);
+       }
+
+       @Test
+       void b03_addCollection_nullCollection() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1");
+               list.aa((Collection<String>)null);
+               list.a("item2");
+
+               assertSize(2, list);
+               assertEquals("item1", list.get(0));
+               assertEquals("item2", list.get(1));
+       }
+
+       @Test
+       void b04_addCollection_emptyCollection() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1");
+               list.aa(List.of());
+               list.a("item2");
+
+               assertSize(2, list);
+               assertEquals("item1", list.get(0));
+               assertEquals("item2", list.get(1));
+       }
+
+       @Test
+       void b05_addCollection_multipleCalls() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.aa(List.of("item1", "item2"));
+               list.aa(List.of("item3", "item4"));
+
+               assertSize(4, list);
+               assertEquals("item1", list.get(0));
+               assertEquals("item2", list.get(1));
+               assertEquals("item3", list.get(2));
+               assertEquals("item4", list.get(3));
+       }
+
+       
//====================================================================================================
+       // ai(boolean, E) method
+       
//====================================================================================================
+
+       @Test
+       void c01_ai_conditionTrue() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").ai(true, "item2").a("item3");
+
+               assertSize(3, list);
+               assertEquals("item1", list.get(0));
+               assertEquals("item2", list.get(1));
+               assertEquals("item3", list.get(2));
+       }
+
+       @Test
+       void c02_ai_conditionFalse() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").ai(false, "item2").a("item3");
+
+               assertSize(2, list);
+               assertEquals("item1", list.get(0));
+               assertEquals("item3", list.get(1));
+       }
+
+       @Test
+       void c03_ai_returnsThis() {
+               var list = new FluentList<>(new ArrayList<String>());
+               var result1 = list.ai(true, "item1");
+               var result2 = list.ai(false, "item2");
+
+               assertSame(list, result1);
+               assertSame(list, result2);
+       }
+
+       @Test
+       void c04_ai_conditionalBuilding() {
+               boolean includeDebug = true;
+               boolean includeTest = false;
+
+               var list = new FluentList<>(new ArrayList<String>())
+                       .a("basic")
+                       .ai(includeDebug, "debug")
+                       .ai(includeTest, "test");
+
+               assertSize(2, list);
+               assertTrue(list.contains("basic"));
+               assertTrue(list.contains("debug"));
+               assertFalse(list.contains("test"));
+       }
+
+       
//====================================================================================================
+       // Method chaining
+       
//====================================================================================================
+
+       @Test
+       void d01_methodChaining() {
+               var list = new FluentList<>(new ArrayList<String>())
+                       .a("item1")
+                       .a("item2")
+                       .ai(true, "item3")
+                       .ai(false, "item4")
+                       .aa(List.of("item5", "item6"));
+
+               assertSize(5, list);
+               assertEquals("item1", list.get(0));
+               assertEquals("item2", list.get(1));
+               assertEquals("item3", list.get(2));
+               assertEquals("item5", list.get(3));
+               assertEquals("item6", list.get(4));
+       }
+
+       
//====================================================================================================
+       // List interface methods
+       
//====================================================================================================
+
+       @Test
+       void e01_listInterface_get() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item2").a("item3");
+
+               assertEquals("item1", list.get(0));
+               assertEquals("item2", list.get(1));
+               assertEquals("item3", list.get(2));
+       }
+
+       @Test
+       void e02_listInterface_size() {
+               var list = new FluentList<>(new ArrayList<String>());
+               assertEquals(0, list.size());
+
+               list.a("item1");
+               assertEquals(1, list.size());
+
+               list.a("item2");
+               assertEquals(2, list.size());
+       }
+
+       @Test
+       void e03_listInterface_add() {
+               var list = new FluentList<>(new ArrayList<String>());
+               assertTrue(list.add("item1"));
+               assertTrue(list.add("item2"));
+
+               assertSize(2, list);
+               assertEquals("item1", list.get(0));
+               assertEquals("item2", list.get(1));
+       }
+
+       @Test
+       void e04_listInterface_addAtIndex() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item3");
+               list.add(1, "item2");
+
+               assertSize(3, list);
+               assertEquals("item1", list.get(0));
+               assertEquals("item2", list.get(1));
+               assertEquals("item3", list.get(2));
+       }
+
+       @Test
+       void e05_listInterface_addAll() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1");
+               assertTrue(list.addAll(List.of("item2", "item3")));
+
+               assertSize(3, list);
+               assertEquals("item1", list.get(0));
+               assertEquals("item2", list.get(1));
+               assertEquals("item3", list.get(2));
+       }
+
+       @Test
+       void e06_listInterface_remove() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item2").a("item3");
+
+               assertTrue(list.remove("item2"));
+               assertSize(2, list);
+               assertEquals("item1", list.get(0));
+               assertEquals("item3", list.get(1));
+       }
+
+       @Test
+       void e07_listInterface_removeAtIndex() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item2").a("item3");
+
+               assertEquals("item2", list.remove(1));
+               assertSize(2, list);
+               assertEquals("item1", list.get(0));
+               assertEquals("item3", list.get(1));
+       }
+
+       @Test
+       void e08_listInterface_set() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item2").a("item3");
+
+               assertEquals("item2", list.set(1, "item2-updated"));
+               assertEquals("item2-updated", list.get(1));
+       }
+
+       @Test
+       void e09_listInterface_indexOf() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item2").a("item1");
+
+               assertEquals(0, list.indexOf("item1"));
+               assertEquals(1, list.indexOf("item2"));
+               assertEquals(-1, list.indexOf("item3"));
+       }
+
+       @Test
+       void e10_listInterface_lastIndexOf() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item2").a("item1");
+
+               assertEquals(2, list.lastIndexOf("item1"));
+               assertEquals(1, list.lastIndexOf("item2"));
+               assertEquals(-1, list.lastIndexOf("item3"));
+       }
+
+       @Test
+       void e11_listInterface_contains() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item2");
+
+               assertTrue(list.contains("item1"));
+               assertTrue(list.contains("item2"));
+               assertFalse(list.contains("item3"));
+       }
+
+       @Test
+       void e12_listInterface_containsAll() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item2").a("item3");
+
+               assertTrue(list.containsAll(List.of("item1", "item2")));
+               assertTrue(list.containsAll(List.of("item1", "item2", 
"item3")));
+               assertFalse(list.containsAll(List.of("item1", "item4")));
+       }
+
+       @Test
+       void e13_listInterface_isEmpty() {
+               var list = new FluentList<>(new ArrayList<String>());
+               assertTrue(list.isEmpty());
+
+               list.a("item1");
+               assertFalse(list.isEmpty());
+       }
+
+       @Test
+       void e14_listInterface_clear() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item2").a("item3");
+
+               list.clear();
+               assertTrue(list.isEmpty());
+               assertSize(0, list);
+       }
+
+       @Test
+       void e15_listInterface_iterator() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item2").a("item3");
+
+               var found = new ArrayList<String>();
+               for (var item : list) {
+                       found.add(item);
+               }
+
+               assertEquals(List.of("item1", "item2", "item3"), found);
+       }
+
+       @Test
+       void e16_listInterface_listIterator() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item2").a("item3");
+
+               var it = list.listIterator();
+               assertTrue(it.hasNext());
+               assertEquals("item1", it.next());
+               assertEquals("item2", it.next());
+               assertTrue(it.hasPrevious());
+               assertEquals("item2", it.previous());
+       }
+
+       @Test
+       void e17_listInterface_subList() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item2").a("item3").a("item4");
+
+               var subList = list.subList(1, 3);
+               assertSize(2, subList);
+               assertEquals("item2", subList.get(0));
+               assertEquals("item3", subList.get(1));
+       }
+
+       @Test
+       void e18_listInterface_toArray() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item2").a("item3");
+
+               var array = list.toArray();
+               assertEquals(3, array.length);
+               assertEquals("item1", array[0]);
+               assertEquals("item2", array[1]);
+               assertEquals("item3", array[2]);
+       }
+
+       @Test
+       void e19_listInterface_toArrayTyped() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item2").a("item3");
+
+               var array = list.toArray(new String[0]);
+               assertEquals(3, array.length);
+               assertEquals("item1", array[0]);
+               assertEquals("item2", array[1]);
+               assertEquals("item3", array[2]);
+       }
+
+       
//====================================================================================================
+       // Different list implementations
+       
//====================================================================================================
+
+       @Test
+       void f01_linkedList() {
+               var list = new FluentList<>(new LinkedList<String>());
+               list.a("item1").a("item2").a("item3");
+
+               assertSize(3, list);
+       }
+
+       @Test
+       void f02_vector() {
+               var list = new FluentList<>(new Vector<String>());
+               list.a("item1").a("item2").a("item3");
+
+               assertSize(3, list);
+       }
+
+       
//====================================================================================================
+       // Edge cases
+       
//====================================================================================================
+
+       @Test
+       void g01_emptyList() {
+               var list = new FluentList<>(new ArrayList<String>());
+
+               assertTrue(list.isEmpty());
+               assertSize(0, list);
+               assertFalse(list.contains("anything"));
+       }
+
+       @Test
+       void g02_removeAll() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item2").a("item3").a("item4");
+
+               assertTrue(list.removeAll(List.of("item2", "item4")));
+               assertSize(2, list);
+               assertEquals("item1", list.get(0));
+               assertEquals("item3", list.get(1));
+       }
+
+       @Test
+       void g03_retainAll() {
+               var list = new FluentList<>(new ArrayList<String>());
+               list.a("item1").a("item2").a("item3").a("item4");
+
+               assertTrue(list.retainAll(List.of("item2", "item4")));
+               assertSize(2, list);
+               assertEquals("item2", list.get(0));
+               assertEquals("item4", list.get(1));
+       }
+}
+
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/commons/collections/FluentMap_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/FluentMap_Test.java
new file mode 100644
index 0000000000..83c15e7d2f
--- /dev/null
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/FluentMap_Test.java
@@ -0,0 +1,441 @@
+/*
+ * 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.commons.collections;
+
+import static org.apache.juneau.commons.utils.CollectionUtils.*;
+import static org.apache.juneau.junit.bct.BctAssertions.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.juneau.*;
+import org.junit.jupiter.api.*;
+
+class FluentMap_Test extends TestBase {
+
+       
//====================================================================================================
+       // Basic functionality - a(K key, V value)
+       
//====================================================================================================
+
+       @Test
+       void a01_addSingleEntry() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1").a("key2", "value2").a("key3", "value3");
+
+               assertSize(3, map);
+               assertEquals("value1", map.get("key1"));
+               assertEquals("value2", map.get("key2"));
+               assertEquals("value3", map.get("key3"));
+       }
+
+       @Test
+       void a02_addSingleEntry_returnsThis() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               var result = map.a("key1", "value1");
+
+               assertSame(map, result);
+       }
+
+       @Test
+       void a03_addSingleEntry_nullValue() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1").a("key2", null).a("key3", "value3");
+
+               assertSize(3, map);
+               assertEquals("value1", map.get("key1"));
+               assertNull(map.get("key2"));
+               assertEquals("value3", map.get("key3"));
+       }
+
+       @Test
+       void a04_addSingleEntry_nullKey() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a(null, "value1").a("key2", "value2");
+
+               assertSize(2, map);
+               assertEquals("value1", map.get(null));
+               assertEquals("value2", map.get("key2"));
+       }
+
+       @Test
+       void a05_addSingleEntry_updateExisting() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1");
+               map.a("key1", "value1-updated");
+
+               assertSize(1, map);
+               assertEquals("value1-updated", map.get("key1"));
+       }
+
+       
//====================================================================================================
+       // a(Map) method
+       
//====================================================================================================
+
+       @Test
+       void b01_addMap() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               var other = map("key1", "value1", "key2", "value2", "key3", 
"value3");
+               map.aa(other);
+
+               assertSize(3, map);
+               assertEquals("value1", map.get("key1"));
+               assertEquals("value2", map.get("key2"));
+               assertEquals("value3", map.get("key3"));
+       }
+
+       @Test
+       void b02_addMap_returnsThis() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               var other = map("key1", "value1", "key2", "value2");
+               var result = map.aa(other);
+
+               assertSame(map, result);
+       }
+
+       @Test
+       void b03_addMap_nullMap() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1");
+               map.aa((Map<String, String>)null);
+               map.a("key2", "value2");
+
+               assertSize(2, map);
+               assertEquals("value1", map.get("key1"));
+               assertEquals("value2", map.get("key2"));
+       }
+
+       @Test
+       void b04_addMap_emptyMap() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1");
+               map.aa(map());
+               map.a("key2", "value2");
+
+               assertSize(2, map);
+               assertEquals("value1", map.get("key1"));
+               assertEquals("value2", map.get("key2"));
+       }
+
+       @Test
+       void b05_addMap_multipleCalls() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.aa(map("key1", "value1", "key2", "value2"));
+               map.aa(map("key3", "value3", "key4", "value4"));
+
+               assertSize(4, map);
+               assertEquals("value1", map.get("key1"));
+               assertEquals("value2", map.get("key2"));
+               assertEquals("value3", map.get("key3"));
+               assertEquals("value4", map.get("key4"));
+       }
+
+       @Test
+       void b06_addMap_overwritesExisting() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1");
+               map.aa(map("key1", "value1-updated", "key2", "value2"));
+
+               assertSize(2, map);
+               assertEquals("value1-updated", map.get("key1"));
+               assertEquals("value2", map.get("key2"));
+       }
+
+       
//====================================================================================================
+       // ai(boolean, K, V) method
+       
//====================================================================================================
+
+       @Test
+       void c01_ai_conditionTrue() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1").ai(true, "key2", "value2").a("key3", 
"value3");
+
+               assertSize(3, map);
+               assertEquals("value1", map.get("key1"));
+               assertEquals("value2", map.get("key2"));
+               assertEquals("value3", map.get("key3"));
+       }
+
+       @Test
+       void c02_ai_conditionFalse() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1").ai(false, "key2", "value2").a("key3", 
"value3");
+
+               assertSize(2, map);
+               assertEquals("value1", map.get("key1"));
+               assertFalse(map.containsKey("key2"));
+               assertEquals("value3", map.get("key3"));
+       }
+
+       @Test
+       void c03_ai_returnsThis() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               var result1 = map.ai(true, "key1", "value1");
+               var result2 = map.ai(false, "key2", "value2");
+
+               assertSame(map, result1);
+               assertSame(map, result2);
+       }
+
+       @Test
+       void c04_ai_conditionalBuilding() {
+               boolean includeDebug = true;
+               boolean includeTest = false;
+
+               var map = new FluentMap<>(new LinkedHashMap<String, String>())
+                       .a("host", "localhost")
+                       .a("port", "8080")
+                       .ai(includeDebug, "debug", "true")
+                       .ai(includeTest, "test", "true");
+
+               assertSize(3, map);
+               assertEquals("localhost", map.get("host"));
+               assertEquals("8080", map.get("port"));
+               assertEquals("true", map.get("debug"));
+               assertFalse(map.containsKey("test"));
+       }
+
+       
//====================================================================================================
+       // Method chaining
+       
//====================================================================================================
+
+       @Test
+       void d01_methodChaining() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>())
+                       .a("key1", "value1")
+                       .a("key2", "value2")
+                       .ai(true, "key3", "value3")
+                       .ai(false, "key4", "value4")
+                       .aa(map("key5", "value5", "key6", "value6"));
+
+               assertSize(5, map);
+               assertEquals("value1", map.get("key1"));
+               assertEquals("value2", map.get("key2"));
+               assertEquals("value3", map.get("key3"));
+               assertEquals("value5", map.get("key5"));
+               assertEquals("value6", map.get("key6"));
+               assertFalse(map.containsKey("key4"));
+       }
+
+       
//====================================================================================================
+       // Map interface methods
+       
//====================================================================================================
+
+       @Test
+       void e01_mapInterface_get() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1").a("key2", "value2");
+
+               assertEquals("value1", map.get("key1"));
+               assertEquals("value2", map.get("key2"));
+               assertNull(map.get("key3"));
+       }
+
+       @Test
+       void e02_mapInterface_put() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               assertNull(map.put("key1", "value1"));
+               assertEquals("value1", map.put("key1", "value1-updated"));
+
+               assertSize(1, map);
+               assertEquals("value1-updated", map.get("key1"));
+       }
+
+       @Test
+       void e03_mapInterface_putAll() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1");
+               map.putAll(map("key2", "value2", "key3", "value3"));
+
+               assertSize(3, map);
+               assertEquals("value1", map.get("key1"));
+               assertEquals("value2", map.get("key2"));
+               assertEquals("value3", map.get("key3"));
+       }
+
+       @Test
+       void e04_mapInterface_remove() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1").a("key2", "value2").a("key3", "value3");
+
+               assertEquals("value2", map.remove("key2"));
+               assertSize(2, map);
+               assertEquals("value1", map.get("key1"));
+               assertFalse(map.containsKey("key2"));
+               assertEquals("value3", map.get("key3"));
+       }
+
+       @Test
+       void e05_mapInterface_containsKey() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1").a("key2", "value2");
+
+               assertTrue(map.containsKey("key1"));
+               assertTrue(map.containsKey("key2"));
+               assertFalse(map.containsKey("key3"));
+       }
+
+       @Test
+       void e06_mapInterface_containsValue() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1").a("key2", "value2");
+
+               assertTrue(map.containsValue("value1"));
+               assertTrue(map.containsValue("value2"));
+               assertFalse(map.containsValue("value3"));
+       }
+
+       @Test
+       void e07_mapInterface_size() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               assertEquals(0, map.size());
+
+               map.a("key1", "value1");
+               assertEquals(1, map.size());
+
+               map.a("key2", "value2");
+               assertEquals(2, map.size());
+       }
+
+       @Test
+       void e08_mapInterface_isEmpty() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               assertTrue(map.isEmpty());
+
+               map.a("key1", "value1");
+               assertFalse(map.isEmpty());
+       }
+
+       @Test
+       void e09_mapInterface_clear() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1").a("key2", "value2").a("key3", "value3");
+
+               map.clear();
+               assertTrue(map.isEmpty());
+               assertSize(0, map);
+       }
+
+       @Test
+       void e10_mapInterface_keySet() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1").a("key2", "value2").a("key3", "value3");
+
+               var keySet = map.keySet();
+               assertSize(3, keySet);
+               assertTrue(keySet.contains("key1"));
+               assertTrue(keySet.contains("key2"));
+               assertTrue(keySet.contains("key3"));
+       }
+
+       @Test
+       void e11_mapInterface_values() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1").a("key2", "value2").a("key3", "value3");
+
+               var values = map.values();
+               assertSize(3, values);
+               assertTrue(values.contains("value1"));
+               assertTrue(values.contains("value2"));
+               assertTrue(values.contains("value3"));
+       }
+
+       @Test
+       void e12_mapInterface_entrySet() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1").a("key2", "value2").a("key3", "value3");
+
+               var entrySet = map.entrySet();
+               assertSize(3, entrySet);
+
+               var found = new LinkedHashSet<String>();
+               for (var entry : entrySet) {
+                       found.add(entry.getKey() + "=" + entry.getValue());
+               }
+               assertTrue(found.contains("key1=value1"));
+               assertTrue(found.contains("key2=value2"));
+               assertTrue(found.contains("key3=value3"));
+       }
+
+       
//====================================================================================================
+       // Different map implementations
+       
//====================================================================================================
+
+       @Test
+       void f01_hashMap() {
+               var map = new FluentMap<>(new HashMap<String, String>());
+               map.a("key1", "value1").a("key2", "value2").a("key3", "value3");
+
+               assertSize(3, map);
+       }
+
+       @Test
+       void f02_treeMap() {
+               var map = new FluentMap<>(new TreeMap<String, String>());
+               map.a("zebra", "value3").a("apple", "value1").a("banana", 
"value2");
+
+               assertSize(3, map);
+               // TreeMap maintains sorted order
+               var keys = new ArrayList<>(map.keySet());
+               assertEquals(List.of("apple", "banana", "zebra"), keys);
+       }
+
+       @Test
+       void f03_concurrentHashMap() {
+               var map = new FluentMap<>(new ConcurrentHashMap<String, 
String>());
+               map.a("key1", "value1").a("key2", "value2").a("key3", "value3");
+
+               assertSize(3, map);
+       }
+
+       
//====================================================================================================
+       // Edge cases
+       
//====================================================================================================
+
+       @Test
+       void g01_emptyMap() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+
+               assertTrue(map.isEmpty());
+               assertSize(0, map);
+               assertFalse(map.containsKey("anything"));
+               assertNull(map.get("anything"));
+       }
+
+       @Test
+       void g02_nullKeyAndValue() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a(null, null).a("key1", "value1");
+
+               assertSize(2, map);
+               assertNull(map.get(null));
+               assertTrue(map.containsKey(null));
+               assertEquals("value1", map.get("key1"));
+       }
+
+       @Test
+       void g03_updateWithNullValue() {
+               var map = new FluentMap<>(new LinkedHashMap<String, String>());
+               map.a("key1", "value1");
+               map.a("key1", null);
+
+               assertSize(1, map);
+               assertTrue(map.containsKey("key1"));
+               assertNull(map.get("key1"));
+       }
+}
+
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/commons/collections/FluentSet_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/FluentSet_Test.java
new file mode 100644
index 0000000000..583577542a
--- /dev/null
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/FluentSet_Test.java
@@ -0,0 +1,416 @@
+/*
+ * 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.commons.collections;
+
+import static org.apache.juneau.junit.bct.BctAssertions.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.junit.jupiter.api.*;
+
+class FluentSet_Test extends TestBase {
+
+       
//====================================================================================================
+       // Basic functionality - a(E element)
+       
//====================================================================================================
+
+       @Test
+       void a01_addSingleElement() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1").a("item2").a("item3");
+
+               assertSize(3, set);
+               assertTrue(set.contains("item1"));
+               assertTrue(set.contains("item2"));
+               assertTrue(set.contains("item3"));
+       }
+
+       @Test
+       void a02_addSingleElement_returnsThis() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               var result = set.a("item1");
+
+               assertSame(set, result);
+       }
+
+       @Test
+       void a03_addSingleElement_nullValue() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1").a(null).a("item3");
+
+               assertSize(3, set);
+               assertTrue(set.contains("item1"));
+               assertTrue(set.contains(null));
+               assertTrue(set.contains("item3"));
+       }
+
+       @Test
+       void a04_addSingleElement_duplicateIgnored() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1").a("item2").a("item1");
+
+               assertSize(2, set);
+               assertTrue(set.contains("item1"));
+               assertTrue(set.contains("item2"));
+       }
+
+       
//====================================================================================================
+       // a(Collection) method
+       
//====================================================================================================
+
+       @Test
+       void b01_addCollection() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               var other = List.of("item1", "item2", "item3");
+               set.aa(other);
+
+               assertSize(3, set);
+               assertTrue(set.contains("item1"));
+               assertTrue(set.contains("item2"));
+               assertTrue(set.contains("item3"));
+       }
+
+       @Test
+       void b02_addCollection_returnsThis() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               var other = List.of("item1", "item2");
+               var result = set.aa(other);
+
+               assertSame(set, result);
+       }
+
+       @Test
+       void b03_addCollection_nullCollection() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1");
+               set.aa((Collection<String>)null);
+               set.a("item2");
+
+               assertSize(2, set);
+               assertTrue(set.contains("item1"));
+               assertTrue(set.contains("item2"));
+       }
+
+       @Test
+       void b04_addCollection_emptyCollection() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1");
+               set.aa(List.of());
+               set.a("item2");
+
+               assertSize(2, set);
+               assertTrue(set.contains("item1"));
+               assertTrue(set.contains("item2"));
+       }
+
+       @Test
+       void b05_addCollection_duplicatesIgnored() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.aa(List.of("item1", "item2"));
+               set.aa(List.of("item2", "item3"));  // item2 is duplicate
+
+               assertSize(3, set);
+               assertTrue(set.contains("item1"));
+               assertTrue(set.contains("item2"));
+               assertTrue(set.contains("item3"));
+       }
+
+       
//====================================================================================================
+       // ai(boolean, E) method
+       
//====================================================================================================
+
+       @Test
+       void c01_ai_conditionTrue() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1").ai(true, "item2").a("item3");
+
+               assertSize(3, set);
+               assertTrue(set.contains("item1"));
+               assertTrue(set.contains("item2"));
+               assertTrue(set.contains("item3"));
+       }
+
+       @Test
+       void c02_ai_conditionFalse() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1").ai(false, "item2").a("item3");
+
+               assertSize(2, set);
+               assertTrue(set.contains("item1"));
+               assertFalse(set.contains("item2"));
+               assertTrue(set.contains("item3"));
+       }
+
+       @Test
+       void c03_ai_returnsThis() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               var result1 = set.ai(true, "item1");
+               var result2 = set.ai(false, "item2");
+
+               assertSame(set, result1);
+               assertSame(set, result2);
+       }
+
+       @Test
+       void c04_ai_conditionalBuilding() {
+               boolean includeDebug = true;
+               boolean includeTest = false;
+
+               var set = new FluentSet<>(new LinkedHashSet<String>())
+                       .a("basic")
+                       .ai(includeDebug, "debug")
+                       .ai(includeTest, "test");
+
+               assertSize(2, set);
+               assertTrue(set.contains("basic"));
+               assertTrue(set.contains("debug"));
+               assertFalse(set.contains("test"));
+       }
+
+       
//====================================================================================================
+       // Method chaining
+       
//====================================================================================================
+
+       @Test
+       void d01_methodChaining() {
+               var set = new FluentSet<>(new LinkedHashSet<String>())
+                       .a("item1")
+                       .a("item2")
+                       .ai(true, "item3")
+                       .ai(false, "item4")
+                       .aa(List.of("item5", "item6"));
+
+               assertSize(5, set);
+               assertTrue(set.contains("item1"));
+               assertTrue(set.contains("item2"));
+               assertTrue(set.contains("item3"));
+               assertTrue(set.contains("item5"));
+               assertTrue(set.contains("item6"));
+               assertFalse(set.contains("item4"));
+       }
+
+       
//====================================================================================================
+       // Set interface methods
+       
//====================================================================================================
+
+       @Test
+       void e01_setInterface_size() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               assertEquals(0, set.size());
+
+               set.a("item1");
+               assertEquals(1, set.size());
+
+               set.a("item2");
+               assertEquals(2, set.size());
+       }
+
+       @Test
+       void e02_setInterface_add() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               assertTrue(set.add("item1"));
+               assertTrue(set.add("item2"));
+               assertFalse(set.add("item1"));  // Duplicate, returns false
+
+               assertSize(2, set);
+               assertTrue(set.contains("item1"));
+               assertTrue(set.contains("item2"));
+       }
+
+       @Test
+       void e03_setInterface_addAll() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1");
+               assertTrue(set.addAll(List.of("item2", "item3")));
+
+               assertSize(3, set);
+               assertTrue(set.contains("item1"));
+               assertTrue(set.contains("item2"));
+               assertTrue(set.contains("item3"));
+       }
+
+       @Test
+       void e04_setInterface_remove() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1").a("item2").a("item3");
+
+               assertTrue(set.remove("item2"));
+               assertSize(2, set);
+               assertTrue(set.contains("item1"));
+               assertFalse(set.contains("item2"));
+               assertTrue(set.contains("item3"));
+       }
+
+       @Test
+       void e05_setInterface_contains() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1").a("item2");
+
+               assertTrue(set.contains("item1"));
+               assertTrue(set.contains("item2"));
+               assertFalse(set.contains("item3"));
+       }
+
+       @Test
+       void e06_setInterface_containsAll() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1").a("item2").a("item3");
+
+               assertTrue(set.containsAll(List.of("item1", "item2")));
+               assertTrue(set.containsAll(List.of("item1", "item2", "item3")));
+               assertFalse(set.containsAll(List.of("item1", "item4")));
+       }
+
+       @Test
+       void e07_setInterface_isEmpty() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               assertTrue(set.isEmpty());
+
+               set.a("item1");
+               assertFalse(set.isEmpty());
+       }
+
+       @Test
+       void e08_setInterface_clear() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1").a("item2").a("item3");
+
+               set.clear();
+               assertTrue(set.isEmpty());
+               assertSize(0, set);
+       }
+
+       @Test
+       void e09_setInterface_iterator() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1").a("item2").a("item3");
+
+               var found = new LinkedHashSet<String>();
+               for (var item : set) {
+                       found.add(item);
+               }
+
+               assertSize(3, found);
+               assertTrue(found.contains("item1"));
+               assertTrue(found.contains("item2"));
+               assertTrue(found.contains("item3"));
+       }
+
+       @Test
+       void e10_setInterface_toArray() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1").a("item2").a("item3");
+
+               var array = set.toArray();
+               assertEquals(3, array.length);
+               // Order may vary, so just check all items are present
+               var arrayList = Arrays.asList(array);
+               assertTrue(arrayList.contains("item1"));
+               assertTrue(arrayList.contains("item2"));
+               assertTrue(arrayList.contains("item3"));
+       }
+
+       @Test
+       void e11_setInterface_toArrayTyped() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1").a("item2").a("item3");
+
+               var array = set.toArray(new String[0]);
+               assertEquals(3, array.length);
+               // Order may vary, so just check all items are present
+               var arrayList = Arrays.asList(array);
+               assertTrue(arrayList.contains("item1"));
+               assertTrue(arrayList.contains("item2"));
+               assertTrue(arrayList.contains("item3"));
+       }
+
+       
//====================================================================================================
+       // Different set implementations
+       
//====================================================================================================
+
+       @Test
+       void f01_hashSet() {
+               var set = new FluentSet<>(new HashSet<String>());
+               set.a("item1").a("item2").a("item3");
+
+               assertSize(3, set);
+       }
+
+       @Test
+       void f02_treeSet() {
+               var set = new FluentSet<>(new TreeSet<String>());
+               set.a("zebra").a("apple").a("banana");
+
+               assertSize(3, set);
+               // TreeSet maintains sorted order
+               var iterator = set.iterator();
+               assertEquals("apple", iterator.next());
+               assertEquals("banana", iterator.next());
+               assertEquals("zebra", iterator.next());
+       }
+
+       
//====================================================================================================
+       // Edge cases
+       
//====================================================================================================
+
+       @Test
+       void g01_emptySet() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+
+               assertTrue(set.isEmpty());
+               assertSize(0, set);
+               assertFalse(set.contains("anything"));
+       }
+
+       @Test
+       void g02_removeAll() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1").a("item2").a("item3").a("item4");
+
+               assertTrue(set.removeAll(List.of("item2", "item4")));
+               assertSize(2, set);
+               assertTrue(set.contains("item1"));
+               assertTrue(set.contains("item3"));
+               assertFalse(set.contains("item2"));
+               assertFalse(set.contains("item4"));
+       }
+
+       @Test
+       void g03_retainAll() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1").a("item2").a("item3").a("item4");
+
+               assertTrue(set.retainAll(List.of("item2", "item4")));
+               assertSize(2, set);
+               assertTrue(set.contains("item2"));
+               assertTrue(set.contains("item4"));
+               assertFalse(set.contains("item1"));
+               assertFalse(set.contains("item3"));
+       }
+
+       @Test
+       void g04_duplicateHandling() {
+               var set = new FluentSet<>(new LinkedHashSet<String>());
+               set.a("item1").a("item1").a("item1");
+
+               assertSize(1, set);
+               assertTrue(set.contains("item1"));
+       }
+}
+

Reply via email to