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 3f871dae3b Utility class modernization
3f871dae3b is described below

commit 3f871dae3b25a3cf273d3e9ce951670358c0fb3e
Author: James Bognar <[email protected]>
AuthorDate: Wed Nov 5 10:48:22 2025 -0500

    Utility class modernization
---
 .../juneau/common/collections/MapBuilder.java      | 102 ++++++++++--
 .../juneau/common/reflect/AnnotationProvider2.java | 184 +++++++++++++++++++++
 .../juneau/common/reflect}/ReflectionMap.java      | 106 ++++++------
 .../juneau/common/utils/CollectionUtils.java       |  36 +++-
 .../apache/juneau/rest/debug/DebugEnablement.java  |   2 +-
 .../juneau/rest/debug/DebugEnablementMap.java      |   2 +-
 .../reflect}/ReflectionMapTest.java                |  30 ++--
 7 files changed, 380 insertions(+), 82 deletions(-)

diff --git 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/collections/MapBuilder.java
 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/collections/MapBuilder.java
index bccfa60cd8..c028470d6c 100644
--- 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/collections/MapBuilder.java
+++ 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/collections/MapBuilder.java
@@ -32,12 +32,17 @@ import org.apache.juneau.common.utils.*;
  * other maps, sorting by keys, and applying modifiers like unmodifiable or 
sparse modes. It's particularly
  * useful when constructing maps dynamically from multiple sources or with 
conditional entries.
  *
+ * <p>
+ * Instances of this builder can be created using {@link #create(Class, 
Class)} or the convenience method
+ * {@link org.apache.juneau.common.utils.CollectionUtils#mapb(Class, Class, 
org.apache.juneau.common.utils.Converter...)}.
+ *
  * <h5 class='section'>Features:</h5>
  * <ul class='spaced-list'>
  *     <li>Fluent API - all methods return <c>this</c> for method chaining
  *     <li>Multiple add methods - single entries, pairs, other maps
  *     <li>Arbitrary input support - automatic type conversion with {@link 
#addAny(Object...)}
  *     <li>Pair adding - {@link #addPairs(Object...)} for varargs key-value 
pairs
+ *     <li>Filtering support - exclude unwanted values via {@link #filtered()} 
or {@link #filtered(java.util.function.Predicate)}
  *     <li>Sorting support - natural key order or custom {@link Comparator}
  *     <li>Sparse mode - return <jk>null</jk> for empty maps
  *     <li>Unmodifiable mode - create immutable maps
@@ -46,20 +51,22 @@ import org.apache.juneau.common.utils.*;
  *
  * <h5 class='section'>Examples:</h5>
  * <p class='bjava'>
+ *     <jk>import static</jk> org.apache.juneau.common.utils.CollectionUtils.*;
+ *
  *     <jc>// Basic usage</jc>
- *     Map&lt;String,Integer&gt; <jv>map</jv> = 
MapBuilder.<jsm>create</jsm>(String.<jk>class</jk>, Integer.<jk>class</jk>)
+ *     Map&lt;String,Integer&gt; <jv>map</jv> = 
<jsm>mapb</jsm>(String.<jk>class</jk>, Integer.<jk>class</jk>)
  *             .add(<js>"one"</js>, 1)
  *             .add(<js>"two"</js>, 2)
  *             .add(<js>"three"</js>, 3)
  *             .build();
  *
  *     <jc>// Using pairs</jc>
- *     Map&lt;String,String&gt; <jv>props</jv> = 
MapBuilder.<jsm>create</jsm>(String.<jk>class</jk>, String.<jk>class</jk>)
+ *     Map&lt;String,String&gt; <jv>props</jv> = 
<jsm>mapb</jsm>(String.<jk>class</jk>, String.<jk>class</jk>)
  *             .addPairs(<js>"host"</js>, <js>"localhost"</js>, 
<js>"port"</js>, <js>"8080"</js>)
  *             .build();
  *
  *     <jc>// With sorting by key</jc>
- *     Map&lt;String,Integer&gt; <jv>sorted</jv> = 
MapBuilder.<jsm>create</jsm>(String.<jk>class</jk>, Integer.<jk>class</jk>)
+ *     Map&lt;String,Integer&gt; <jv>sorted</jv> = 
<jsm>mapb</jsm>(String.<jk>class</jk>, Integer.<jk>class</jk>)
  *             .add(<js>"zebra"</js>, 3)
  *             .add(<js>"apple"</js>, 1)
  *             .add(<js>"banana"</js>, 2)
@@ -67,7 +74,7 @@ import org.apache.juneau.common.utils.*;
  *             .build();  <jc>// Returns TreeMap with natural key order</jc>
  *
  *     <jc>// Immutable map</jc>
- *     Map&lt;String,String&gt; <jv>config</jv> = 
MapBuilder.<jsm>create</jsm>(String.<jk>class</jk>, String.<jk>class</jk>)
+ *     Map&lt;String,String&gt; <jv>config</jv> = 
<jsm>mapb</jsm>(String.<jk>class</jk>, String.<jk>class</jk>)
  *             .add(<js>"env"</js>, <js>"prod"</js>)
  *             .add(<js>"region"</js>, <js>"us-west"</js>)
  *             .unmodifiable()
@@ -75,13 +82,13 @@ import org.apache.juneau.common.utils.*;
  *
  *     <jc>// From multiple sources</jc>
  *     Map&lt;String,Integer&gt; <jv>existing</jv> = Map.of(<js>"a"</js>, 1, 
<js>"b"</js>, 2);
- *     Map&lt;String,Integer&gt; <jv>combined</jv> = 
MapBuilder.<jsm>create</jsm>(String.<jk>class</jk>, Integer.<jk>class</jk>)
+ *     Map&lt;String,Integer&gt; <jv>combined</jv> = 
<jsm>mapb</jsm>(String.<jk>class</jk>, Integer.<jk>class</jk>)
  *             .addAll(<jv>existing</jv>)
  *             .add(<js>"c"</js>, 3)
  *             .build();
  *
  *     <jc>// Sparse mode - returns null when empty</jc>
- *     Map&lt;String,String&gt; <jv>maybeNull</jv> = 
MapBuilder.<jsm>create</jsm>(String.<jk>class</jk>, String.<jk>class</jk>)
+ *     Map&lt;String,String&gt; <jv>maybeNull</jv> = 
<jsm>mapb</jsm>(String.<jk>class</jk>, String.<jk>class</jk>)
  *             .sparse()
  *             .build();  <jc>// Returns null, not empty map</jc>
  * </p>
@@ -105,6 +112,7 @@ public class MapBuilder<K,V> {
        private Map<K,V> map;
        private boolean unmodifiable = false, sparse = false;
        private Comparator<K> comparator;
+       private java.util.function.Predicate<Object> filter;
 
        private Class<K> keyType;
        private Class<V> valueType;
@@ -151,11 +159,17 @@ public class MapBuilder<K,V> {
        /**
         * Adds a single entry to this map.
         *
+        * <p>
+        * If a filter has been set via {@link 
#filtered(java.util.function.Predicate)} or {@link #filtered()},
+        * the value will only be added if it passes the filter (i.e., the 
filter returns {@code true}).
+        *
         * @param key The map key.
         * @param value The map value.
         * @return This object.
         */
        public MapBuilder<K,V> add(K key, V value) {
+               if (filter != null && !filter.test(value))
+                       return this;
                if (map == null)
                        map = new LinkedHashMap<>();
                map.put(key, value);
@@ -168,15 +182,16 @@ public class MapBuilder<K,V> {
         * <p>
         * This is a no-op if the value is <jk>null</jk>.
         *
+        * <p>
+        * If a filter has been set, each value will be filtered before being 
added.
+        *
         * @param value The map to add to this map.
         * @return This object.
         */
        public MapBuilder<K,V> addAll(Map<K,V> value) {
                if (nn(value)) {
-                       if (map == null)
-                               map = new LinkedHashMap<>(value);
-                       else
-                               map.putAll(value);
+                       for (Map.Entry<K,V> entry : value.entrySet())
+                               add(entry.getKey(), entry.getValue());
                }
                return this;
        }
@@ -308,6 +323,73 @@ public class MapBuilder<K,V> {
                return this;
        }
 
+       /**
+        * Applies a filter predicate to values added via {@link #add(Object, 
Object)}.
+        *
+        * <p>
+        * Values where the predicate returns {@code true} will be kept; values 
where it returns {@code false} will not be added.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      <jk>import static</jk> 
org.apache.juneau.common.utils.CollectionUtils.*;
+        *
+        *      <jc>// Keep only non-null, non-empty string values</jc>
+        *      Map&lt;String,String&gt; <jv>map</jv> = 
<jsm>mapb</jsm>(String.<jk>class</jk>, String.<jk>class</jk>)
+        *              .filtered(<jv>x</jv> -&gt; <jv>x</jv> != <jk>null</jk> 
&amp;&amp; !<jv>x</jv>.equals(<js>""</js>))
+        *              .add(<js>"a"</js>, <js>"foo"</js>)
+        *              .add(<js>"b"</js>, <jk>null</jk>)     <jc>// Not 
added</jc>
+        *              .add(<js>"c"</js>, <js>""</js>)       <jc>// Not 
added</jc>
+        *              .build();
+        * </p>
+        *
+        * @param filter The filter predicate.
+        * @return This object.
+        */
+       public MapBuilder<K,V> filtered(java.util.function.Predicate<Object> 
filter) {
+               this.filter = filter;
+               return this;
+       }
+
+       /**
+        * Applies a default filter that excludes common "empty" or "unset" 
values from being added to the map.
+        *
+        * <p>
+        * The following values are filtered out:
+        * <ul>
+        *      <li>{@code null}
+        *      <li>{@link Boolean#FALSE}
+        *      <li>Numbers with {@code intValue() == -1}
+        *      <li>Empty arrays
+        *      <li>Empty {@link Map Maps}
+        *      <li>Empty {@link Collection Collections}
+        * </ul>
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      <jk>import static</jk> 
org.apache.juneau.common.utils.CollectionUtils.*;
+        *
+        *      Map&lt;String,Object&gt; <jv>map</jv> = 
<jsm>mapb</jsm>(String.<jk>class</jk>, Object.<jk>class</jk>)
+        *              .filtered()
+        *              .add(<js>"name"</js>, <js>"John"</js>)
+        *              .add(<js>"age"</js>, -1)              <jc>// Not 
added</jc>
+        *              .add(<js>"enabled"</js>, <jk>false</jk>)   <jc>// Not 
added</jc>
+        *              .add(<js>"tags"</js>, <jk>new</jk> String[0]) <jc>// 
Not added</jc>
+        *              .build();
+        * </p>
+        *
+        * @return This object.
+        */
+       public MapBuilder<K,V> filtered() {
+               return filtered(x -> ! (
+                       x == null
+                       || (x instanceof Boolean && x.equals(false))
+                       || (x instanceof Number && ((Number)x).intValue() == -1)
+                       || (isArray(x) && java.lang.reflect.Array.getLength(x) 
== 0)
+                       || (x instanceof Map && ((Map<?,?>)x).isEmpty())
+                       || (x instanceof Collection && 
((Collection<?>)x).isEmpty())
+               ));
+       }
+
        /**
         * Converts the set into a {@link SortedMap}.
         *
diff --git 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/AnnotationProvider2.java
 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/AnnotationProvider2.java
new file mode 100644
index 0000000000..3674c9ae99
--- /dev/null
+++ 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/AnnotationProvider2.java
@@ -0,0 +1,184 @@
+/*
+ * 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.common.reflect;
+
+import static org.apache.juneau.common.utils.AssertionUtils.*;
+import static org.apache.juneau.common.utils.ClassUtils.*;
+import static org.apache.juneau.common.utils.CollectionUtils.*;
+import static org.apache.juneau.common.utils.Utils.*;
+
+import java.lang.annotation.*;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.stream.*;
+
+import org.apache.juneau.common.collections.*;
+
+/**
+ * Enhanced annotation provider for classes that returns {@link 
AnnotationInfo} objects instead of raw {@link Annotation} objects.
+ *
+ * <p>
+ * This class provides a modern API for retrieving class annotations with the 
following benefits:
+ * <ul>
+ *     <li>Returns {@link AnnotationInfo} wrappers that provide additional 
methods and type safety
+ *     <li>Supports filtering by annotation type using streams
+ *     <li>Properly handles repeatable annotations
+ *     <li>Searches up the class hierarchy (class → parents → interfaces → 
package)
+ *     <li>Caches results for performance
+ * </ul>
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ *     <li class='jc'>{@link AnnotationProvider}
+ *     <li class='jc'>{@link AnnotationInfo}
+ * </ul>
+ */
+public class AnnotationProvider2 {
+
+       /**
+        * Disable annotation caching.
+        */
+       private static final boolean DISABLE_ANNOTATION_CACHING = 
Boolean.getBoolean("juneau.disableAnnotationCaching");
+
+       /**
+        * Default instance.
+        */
+       public static final AnnotationProvider2 INSTANCE = new 
AnnotationProvider2();
+
+       // @formatter:off
+       private final Cache<Class<?>,List<AnnotationInfo<Annotation>>> 
classAnnotationsInfo = _buildClassAnnotationsCache();
+       // @formatter:on
+
+       @SuppressWarnings("unchecked")
+       private Cache<Class<?>,List<AnnotationInfo<Annotation>>> 
_buildClassAnnotationsCache() {
+               var builder = Cache.of(Class.class, 
List.class).supplier(this::findClassAnnotations);
+               if (DISABLE_ANNOTATION_CACHING)
+                       builder.disableCaching();
+               return 
(Cache<Class<?>,List<AnnotationInfo<Annotation>>>)(Cache<?,?>)builder.build();
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Public API
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       /**
+        * Finds all annotations on the specified class.
+        *
+        * <p>
+        * Returns annotations in child-to-parent order.
+        *
+        * @param onClass The class to search on.
+        * @return A list of {@link AnnotationInfo} objects representing 
annotations on the specified class and its parents.
+        *      Never <jk>null</jk>.
+        */
+       public List<AnnotationInfo<Annotation>> find(Class<?> onClass) {
+               assertArgNotNull("onClass", onClass);
+               return classAnnotationsInfo.get(onClass);
+       }
+
+       /**
+        * Finds all annotations of the specified type on the specified class.
+        *
+        * <p>
+        * Returns annotations in child-to-parent order.
+        *
+        * @param <A> The annotation type to find.
+        * @param type The annotation type to find.
+        * @param onClass The class to search on.
+        * @return A stream of {@link AnnotationInfo} objects representing 
annotations of the specified type on the specified class and its parents.
+        *      Never <jk>null</jk>.
+        */
+       @SuppressWarnings("unchecked")
+       public <A extends Annotation> Stream<AnnotationInfo<A>> find(Class<A> 
type, Class<?> onClass) {
+               assertArgNotNull("type", type);
+               assertArgNotNull("onClass", onClass);
+               return find(onClass).stream()
+                       .filter(a -> a.isType(type))
+                       .map(a -> (AnnotationInfo<A>)a);
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Private implementation
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       /**
+        * Finds all annotations on the specified class in child-to-parent 
order.
+        *
+        * <p>
+        * Annotations are appended in the following order:
+        * <ol>
+        *      <li>On this class.
+        *      <li>On parent classes ordered child-to-parent.
+        *      <li>On interfaces ordered child-to-parent.
+        *      <li>On the package of this class.
+        * </ol>
+        *
+        * @param forClass The class to find annotations on.
+        * @return A list of {@link AnnotationInfo} objects in child-to-parent 
order.
+        */
+       private List<AnnotationInfo<Annotation>> findClassAnnotations(Class<?> 
forClass) {
+               var ci = ClassInfo.of(forClass);
+               var list = new ArrayList<AnnotationInfo<Annotation>>();
+               
+               // On this class
+               findDeclaredAnnotations(list, forClass);
+               
+               // On parent classes ordered child-to-parent
+               var parents = ci.getParents();
+               for (int i = 0; i < parents.size(); i++)
+                       findDeclaredAnnotations(list, parents.get(i).inner());
+               
+               // On interfaces ordered child-to-parent
+               var interfaces = ci.getInterfaces();
+               for (int i = 0; i < interfaces.size(); i++)
+                       findDeclaredAnnotations(list, 
interfaces.get(i).inner());
+               
+               // On the package of this class
+               var pkg = ci.getPackage();
+               if (nn(pkg))
+                       findDeclaredAnnotations(list, pkg.inner());
+               
+               return u(list);
+       }
+
+       /**
+        * Finds all declared annotations on the specified class and appends 
them to the list.
+        *
+        * @param appendTo The list to append to.
+        * @param forClass The class to find declared annotations on.
+        */
+       private void findDeclaredAnnotations(List<AnnotationInfo<Annotation>> 
appendTo, Class<?> forClass) {
+               var ci = ClassInfo.of(forClass);
+               for (var a : forClass.getDeclaredAnnotations())
+                       for (var a2 : splitRepeated(a))
+                               appendTo.add(AnnotationInfo.of(ci, a2));
+       }
+
+       /**
+        * Finds all annotations on the specified package and appends them to 
the list.
+        *
+        * @param appendTo The list to append to.
+        * @param forPackage The package to find annotations on.
+        */
+       private void findDeclaredAnnotations(List<AnnotationInfo<Annotation>> 
appendTo, Package forPackage) {
+               var pi = PackageInfo.of(forPackage);
+               for (var a : forPackage.getAnnotations())
+                       for (var a2 : splitRepeated(a))
+                               appendTo.add(AnnotationInfo.of(pi, a2));
+       }
+}
+
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ReflectionMap.java
 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/ReflectionMap.java
similarity index 94%
rename from 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ReflectionMap.java
rename to 
juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/ReflectionMap.java
index b30319c4ef..9865a62f4c 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ReflectionMap.java
+++ 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/ReflectionMap.java
@@ -14,10 +14,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.juneau.utils;
+package org.apache.juneau.common.reflect;
 
 import static java.lang.Character.*;
-import static org.apache.juneau.collections.JsonMap.*;
 import static org.apache.juneau.common.utils.CollectionUtils.*;
 import static org.apache.juneau.common.utils.StringUtils.*;
 import static org.apache.juneau.common.utils.ThrowableUtils.*;
@@ -248,16 +247,16 @@ public class ReflectionMap<V> {
                        return classMatches(simpleName, fullName, c);
                }
 
-               @Override
-               public String toString() {
-                       // @formatter:off
-                       return filteredMap()
-                               .append("simpleName", simpleName)
-                               .append("fullName", fullName)
-                               .append("value", value)
-                               .asString();
-                       // @formatter:on
-               }
+       @Override
+       public String toString() {
+               // @formatter:off
+               return mapb().filtered()
+                       .add("simpleName", simpleName)
+                       .add("fullName", fullName)
+                       .add("value", value)
+                       .toString();
+               // @formatter:on
+       }
        }
 
        static class ConstructorEntry<V> {
@@ -280,17 +279,17 @@ public class ReflectionMap<V> {
                        return classMatches(simpleClassName, fullClassName, c) 
&& (argsMatch(args, m.getParameterTypes()));
                }
 
-               @Override
-               public String toString() {
-                       // @formatter:off
-                       return filteredMap()
-                               .append("simpleClassName", simpleClassName)
-                               .append("fullClassName", fullClassName)
-                               .append("args", args)
-                               .append("value", value)
-                               .asString();
-                       // @formatter:on
-               }
+       @Override
+       public String toString() {
+               // @formatter:off
+               return mapb().filtered()
+                       .add("simpleClassName", simpleClassName)
+                       .add("fullClassName", fullClassName)
+                       .add("args", args)
+                       .add("value", value)
+                       .toString();
+               // @formatter:on
+       }
        }
 
        static class FieldEntry<V> {
@@ -314,17 +313,17 @@ public class ReflectionMap<V> {
                        return classMatches(simpleClassName, fullClassName, c) 
&& (eq(f.getName(), fieldName));
                }
 
-               @Override
-               public String toString() {
-                       // @formatter:off
-                       return filteredMap()
-                               .append("simpleClassName", simpleClassName)
-                               .append("fullClassName", fullClassName)
-                               .append("fieldName", fieldName)
-                               .append("value", value)
-                               .asString();
-                       // @formatter:on
-               }
+       @Override
+       public String toString() {
+               // @formatter:off
+               return mapb().filtered()
+                       .add("simpleClassName", simpleClassName)
+                       .add("fullClassName", fullClassName)
+                       .add("fieldName", fieldName)
+                       .add("value", value)
+                       .toString();
+               // @formatter:on
+       }
        }
 
        static class MethodEntry<V> {
@@ -379,18 +378,18 @@ public class ReflectionMap<V> {
                        // @formatter:on
                }
 
-               @Override
-               public String toString() {
-                       // @formatter:off
-                       return filteredMap()
-                               .append("simpleClassName", simpleClassName)
-                               .append("fullClassName", fullClassName)
-                               .append("methodName", methodName)
-                               .append("args", args)
-                               .append("value", value)
-                               .asString();
-                       // @formatter:on
-               }
+       @Override
+       public String toString() {
+               // @formatter:off
+               return mapb().filtered()
+                       .add("simpleClassName", simpleClassName)
+                       .add("fullClassName", fullClassName)
+                       .add("methodName", methodName)
+                       .add("args", args)
+                       .add("value", value)
+                       .toString();
+               // @formatter:on
+       }
        }
 
        /**
@@ -811,12 +810,13 @@ public class ReflectionMap<V> {
        @Override /* Overridden from Object */
        public String toString() {
                // @formatter:off
-               return filteredMap()
-                       .append("classEntries", classEntries)
-                       .append("methodEntries", methodEntries)
-                       .append("fieldEntries", fieldEntries)
-                       .append("constructorEntries", constructorEntries)
-                       .asString();
+               return mapb().filtered()
+                       .add("classEntries", classEntries)
+                       .add("methodEntries", methodEntries)
+                       .add("fieldEntries", fieldEntries)
+                       .add("constructorEntries", constructorEntries)
+                       .toString();
                // @formatter:on
        }
-}
\ No newline at end of file
+}
+
diff --git 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/CollectionUtils.java
 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/CollectionUtils.java
index 66c6725e59..de1211abf5 100644
--- 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/CollectionUtils.java
+++ 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/CollectionUtils.java
@@ -1195,6 +1195,38 @@ public class CollectionUtils {
                return MapBuilder.create(keyType, 
valueType).converters(converters);
        }
 
+       /**
+        * Convenience factory for a {@link MapBuilder} with {@link String} 
keys and {@link Object} values.
+        *
+        * <p>
+        * This is a shortcut for <c>MapBuilder.create(String.<jk>class</jk>, 
Object.<jk>class</jk>)</c>.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      Map&lt;String,Object&gt; <jv>map</jv> = mapb()
+        *              .add(<js>"foo"</js>, 1)
+        *              .add(<js>"bar"</js>, 2)
+        *              .build();
+        * </p>
+        *
+        * <p>
+        * This builder supports optional filtering to automatically exclude 
unwanted values:
+        * <p class='bjava'>
+        *      <jc>// Build a map excluding null and empty values</jc>
+        *      Map&lt;String,Object&gt; <jv>map</jv> = mapb().filtered()
+        *              .add(<js>"foo"</js>, <jk>null</jk>)       <jc>// 
Excluded</jc>
+        *              .add(<js>"bar"</js>, <js>""</js>)         <jc>// 
Excluded</jc>
+        *              .add(<js>"baz"</js>, <js>"value"</js>)    <jc>// 
Included</jc>
+        *              .build();
+        * </p>
+        *
+        * @return A new map builder.
+        * @see MapBuilder
+        */
+       public static MapBuilder<String,Object> mapb() {
+               return MapBuilder.create(String.class, Object.class);
+       }
+
        /**
         * Creates a new {@link TreeSet} containing a copy of the specified set.
         *
@@ -2159,10 +2191,10 @@ public class CollectionUtils {
         * <h5 class='section'>Example:</h5>
         * <p class='bjava'>
         *      String[] <jv>array</jv> = {<js>"a"</js>, <js>"b"</js>, 
<js>"c"</js>};
-        *      
+        *
         *      <jc>// Prints "a", "b", "c"</jc>
         *      
<jsm>stream</jsm>(<jv>array</jv>).forEach(System.<jk>out</jk>::println);
-        *      
+        *
         *      <jc>// Handles null gracefully - returns empty stream</jc>
         *      
<jsm>stream</jsm>(<jk>null</jk>).forEach(System.<jk>out</jk>::println);  <jc>// 
Prints nothing</jc>
         * </p>
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/DebugEnablement.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/DebugEnablement.java
index 9ed343c1ee..99c33132c7 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/DebugEnablement.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/DebugEnablement.java
@@ -24,11 +24,11 @@ import java.lang.reflect.Method;
 import java.util.function.*;
 
 import org.apache.juneau.*;
+import org.apache.juneau.common.reflect.*;
 import org.apache.juneau.cp.*;
 import org.apache.juneau.http.response.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.utils.*;
 
 import jakarta.servlet.http.*;
 
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/DebugEnablementMap.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/DebugEnablementMap.java
index 451e318c60..2eb384c6ce 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/DebugEnablementMap.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/DebugEnablementMap.java
@@ -17,7 +17,7 @@
 package org.apache.juneau.rest.debug;
 
 import org.apache.juneau.*;
-import org.apache.juneau.utils.*;
+import org.apache.juneau.common.reflect.*;
 
 /**
  * A reflection map for the {@link Enablement} setting.
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/utils/ReflectionMapTest.java 
b/juneau-utest/src/test/java/org/apache/juneau/common/reflect/ReflectionMapTest.java
similarity index 91%
rename from 
juneau-utest/src/test/java/org/apache/juneau/utils/ReflectionMapTest.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/common/reflect/ReflectionMapTest.java
index ceafc780d4..23ffa281c4 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/utils/ReflectionMapTest.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/common/reflect/ReflectionMapTest.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.juneau.utils;
+package org.apache.juneau.common.reflect;
 
 import static org.apache.juneau.TestUtils.*;
 import static org.apache.juneau.junit.bct.BctAssertions.*;
@@ -48,7 +48,7 @@ class ReflectionMapTest extends TestBase {
        static ReflectionMap<Number>
                A1_SIMPLE = create().append("A1", 1).build(),
                A1b_SIMPLE = create().append("ReflectionMapTest$A1", 1).build(),
-               A1_FULL = 
create().append("org.apache.juneau.utils.ReflectionMapTest$A1", 1).build();  // 
Note this could be a static field.
+               A1_FULL = 
create().append("org.apache.juneau.common.reflect.ReflectionMapTest$A1", 
1).build();  // Note this could be a static field.
 
        @Test void a01_classNames_checkEntries() {
                checkEntries(A1_SIMPLE, true, false, false, false);
@@ -109,12 +109,12 @@ class ReflectionMapTest extends TestBase {
                B1m1ss_SIMPLE = create().append("B1.m1(java.lang.String)", 
1).build(),
                B1m1si_SIMPLE = create().append("B1.m1(String,int)", 1).build(),
                B1m1ssi_SIMPLE = create().append("B1.m1(java.lang.String , 
int)", 1).build(),
-               B1m1_FULL = 
create().append("org.apache.juneau.utils.ReflectionMapTest$B1.m1", 1).build(),
-               B1m1i_FULL = 
create().append("org.apache.juneau.utils.ReflectionMapTest$B1.m1(int)", 
1).build(),
-               B1m1s_FULL = 
create().append("org.apache.juneau.utils.ReflectionMapTest$B1.m1(String)", 
1).build(),
-               B1m1ss_FULL = 
create().append("org.apache.juneau.utils.ReflectionMapTest$B1.m1(java.lang.String)",
 1).build(),
-               B1m1si_FULL = 
create().append("org.apache.juneau.utils.ReflectionMapTest$B1.m1(String,int)", 
1).build(),
-               B1m1ssi_FULL = 
create().append("org.apache.juneau.utils.ReflectionMapTest$B1.m1(java.lang.String
 , int)", 1).build();
+               B1m1_FULL = 
create().append("org.apache.juneau.common.reflect.ReflectionMapTest$B1.m1", 
1).build(),
+               B1m1i_FULL = 
create().append("org.apache.juneau.common.reflect.ReflectionMapTest$B1.m1(int)",
 1).build(),
+               B1m1s_FULL = 
create().append("org.apache.juneau.common.reflect.ReflectionMapTest$B1.m1(String)",
 1).build(),
+               B1m1ss_FULL = 
create().append("org.apache.juneau.common.reflect.ReflectionMapTest$B1.m1(java.lang.String)",
 1).build(),
+               B1m1si_FULL = 
create().append("org.apache.juneau.common.reflect.ReflectionMapTest$B1.m1(String,int)",
 1).build(),
+               B1m1ssi_FULL = 
create().append("org.apache.juneau.common.reflect.ReflectionMapTest$B1.m1(java.lang.String
 , int)", 1).build();
 
        @Test void b01_methodNames_checkEntries() {
                checkEntries(B1m1_SIMPLE, false, true, true, false);
@@ -199,7 +199,7 @@ class ReflectionMapTest extends TestBase {
 
        static ReflectionMap<Number>
                C1f1_SIMPLE = create().append("C1.f1", 1).build(),
-               C1f1_FULL = 
create().append("org.apache.juneau.utils.ReflectionMapTest$C1.f1", 1).build();
+               C1f1_FULL = 
create().append("org.apache.juneau.common.reflect.ReflectionMapTest$C1.f1", 
1).build();
 
        @Test void c01_fieldNames_checkEntries() {
                checkEntries(C1f1_SIMPLE, false, true, true, false);
@@ -245,12 +245,12 @@ class ReflectionMapTest extends TestBase {
                Dss_SIMPLE = create().append("D1(java.lang.String)", 1).build(),
                Dsi_SIMPLE = create().append("D1(String, int)", 1).build(),
                Dssi_SIMPLE = create().append("D1(java.lang.String, int)", 
1).build(),
-               D_FULL = 
create().append("org.apache.juneau.utils.ReflectionMapTest$D1()", 1).build(),
-               Di_FULL = 
create().append("org.apache.juneau.utils.ReflectionMapTest$D1(int)", 1).build(),
-               Ds_FULL = 
create().append("org.apache.juneau.utils.ReflectionMapTest$D1(String)", 
1).build(),
-               Dss_FULL = 
create().append("org.apache.juneau.utils.ReflectionMapTest$D1(java.lang.String)",
 1).build(),
-               Dsi_FULL = 
create().append("org.apache.juneau.utils.ReflectionMapTest$D1(String, int)", 
1).build(),
-               Dssi_FULL = 
create().append("org.apache.juneau.utils.ReflectionMapTest$D1(java.lang.String, 
int)", 1).build();
+               D_FULL = 
create().append("org.apache.juneau.common.reflect.ReflectionMapTest$D1()", 
1).build(),
+               Di_FULL = 
create().append("org.apache.juneau.common.reflect.ReflectionMapTest$D1(int)", 
1).build(),
+               Ds_FULL = 
create().append("org.apache.juneau.common.reflect.ReflectionMapTest$D1(String)",
 1).build(),
+               Dss_FULL = 
create().append("org.apache.juneau.common.reflect.ReflectionMapTest$D1(java.lang.String)",
 1).build(),
+               Dsi_FULL = 
create().append("org.apache.juneau.common.reflect.ReflectionMapTest$D1(String, 
int)", 1).build(),
+               Dssi_FULL = 
create().append("org.apache.juneau.common.reflect.ReflectionMapTest$D1(java.lang.String,
 int)", 1).build();
 
        @Test void d01_constructorNames_checkEntries() {
                checkEntries(D_SIMPLE, false, false, false, true);

Reply via email to