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 1cda0d8c59 Clean up ConverterUtils
1cda0d8c59 is described below

commit 1cda0d8c595c9b5360394d0e37ab4dc82802fce6
Author: James Bognar <[email protected]>
AuthorDate: Thu Apr 2 07:15:27 2026 -0700

    Clean up ConverterUtils
---
 RELEASE-NOTES.txt                                  |  55 ++++++++
 docs/src/javadoc/overview.html                     |   1 +
 .../org/apache/juneau/bean/html5/HtmlElement.java  |   7 +-
 .../juneau/bean/html5/HtmlElementContainer.java    |   7 +-
 .../apache/juneau/bean/html5/HtmlElementMixed.java |   7 +-
 .../org/apache/juneau/internal/ConverterUtils.java | 147 ++-------------------
 .../org/apache/juneau/swap/AutoNumberSwap.java     |   4 +-
 7 files changed, 77 insertions(+), 151 deletions(-)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 9bb958b36b..25af15dcd0 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -168,6 +168,61 @@ Release Notes - Juneau - Version 9.2.1 - YYYY-MM-DD
       use ISO 8601 formatting for date/time/Duration types.
     * All parser sessions updated with date/time/Duration dispatch in 
parseAnything().
 
+** New Features - Converter Framework (juneau-commons)
+
+    * New org.apache.juneau.commons.conversion package providing a 
lightweight, BeanContext-free
+      type conversion framework:
+
+    * Converter interface:
+        - canConvert(Class<?> inType, Class<?> outType) - default returns 
true; override to restrict.
+        - to(Object o, Class<T> type) - converts o to the target class; throws 
InvalidConversionException
+          if no conversion path exists; returns null only when input is null.
+        - to(Object o, Type mainType, Type... args) - parameterized-type 
variant for generic targets
+          such as List<String> or Map<String,Integer>.
+
+    * CachingConverter abstract class:
+        - Abstract base class implementing Converter with two-level 
ConcurrentHashMap cache.
+        - Conversion functions are discovered once via findConversion(Class, 
Class) and cached for
+          all subsequent calls on the same type pair.
+        - Unconvertable type pairs are also cached (via a NO_CONVERSION 
sentinel) to avoid repeated
+          reflection overhead.
+        - Subclasses implement findConversion(Class<I>, Class<O>) and return a 
Conversion<I,O> lambda,
+          or null if no conversion is possible for that type pair.
+
+    * BasicConverter class:
+        - Concrete CachingConverter with a thread-safe BasicConverter.INSTANCE 
singleton.
+        - Supports a wide range of common conversions without requiring 
BeanContext/BeanSession:
+            - Identity / widening cast (any type to same or supertype).
+            - Numeric narrowing/widening: Number to Integer, Long, Short, 
Float, Double, Byte,
+              AtomicInteger, AtomicLong, and primitive equivalents.
+            - Boolean to Number (true=1, false=0) and Number to Boolean 
(intValue() != 0).
+            - CharSequence to Number (parsed via StringUtils.parseNumber()).
+            - CharSequence (length 1) or Number to Character.
+            - Any type to String (toString() with array support via 
Arrays.toString()).
+            - CharSequence to Enum (Enum.valueOf()).
+            - Collection/array to Collection subtype (copies elements; element 
type from args[0]).
+            - Map to Map subtype (copies entries; key/value types from 
args[0]/args[1]).
+            - Collection/array to array (element type from 
outType.getComponentType()).
+            - Special cases: String ↔ TimeZone, String ↔ Locale.
+            - Reflection-based static factory lookup:
+                
fromString/valueOf/of/from/parse/create/forName/fromValue/builder(X)
+                or dynamic fromX/forX/parseX where X is the input class name.
+            - Reflection-based constructor lookup: public T(X) constructor.
+            - Instance toX() method lookup (e.g. toInteger()).
+
+    * Conversion functional interface:
+        - O to(I in, Class<?>... args) - used as the cached conversion lambda 
in CachingConverter.
+        - args carries type arguments for parameterized output types at call 
time.
+
+    * InvalidConversionException runtime exception:
+        - Thrown by Converter.to() when no conversion path exists between two 
types.
+        - Message format: "Cannot convert <inType> to <outType>".
+        - Callers can pre-check with canConvert() to avoid the exception.
+
+    * BeanContextConverter (renamed from GenericConverter) in 
org.apache.juneau.utils:
+        - Implements Converter and delegates to the default BeanContext 
session for type conversion.
+        - Provides access to the full Juneau framework conversion logic 
including bean mapping.
+
 Release Notes - Juneau - Version 9.2.0 - 2025-12-30
 
 ** Changes
diff --git a/docs/src/javadoc/overview.html b/docs/src/javadoc/overview.html
index d2b158d457..2fa7179f41 100644
--- a/docs/src/javadoc/overview.html
+++ b/docs/src/javadoc/overview.html
@@ -25,6 +25,7 @@
                <li><strong>Microservices</strong> - Build lightweight, 
standalone microservices with embedded Jetty</li>
                <li><strong>Configuration Management</strong> - Sophisticated 
configuration file API with variable resolution</li>
                <li><strong>Fluent Assertions</strong> - Powerful testing 
framework with fluent-style assertions</li>
+               <li><strong>Type Conversion</strong> - Lightweight, 
BeanContext-free converter framework with caching and broad type support</li>
                <li><strong>Zero Dependencies</strong> - Core marshalling 
requires no external dependencies</li>
        </ul>
 
diff --git 
a/juneau-bean/juneau-bean-html5/src/main/java/org/apache/juneau/bean/html5/HtmlElement.java
 
b/juneau-bean/juneau-bean-html5/src/main/java/org/apache/juneau/bean/html5/HtmlElement.java
index 303eb3de87..acf62d369d 100644
--- 
a/juneau-bean/juneau-bean-html5/src/main/java/org/apache/juneau/bean/html5/HtmlElement.java
+++ 
b/juneau-bean/juneau-bean-html5/src/main/java/org/apache/juneau/bean/html5/HtmlElement.java
@@ -26,8 +26,8 @@ import java.net.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
+import org.apache.juneau.commons.conversion.*;
 import org.apache.juneau.html.*;
-import org.apache.juneau.internal.*;
 import org.apache.juneau.xml.annotation.*;
 
 /**
@@ -177,12 +177,13 @@ public abstract class HtmlElement {
         * @param <T> The class type to convert this class to.
         * @param type
         *      The class type to convert this class to.
-        *      See {@link ConverterUtils} for a list of supported conversion 
types.
+        *      See {@link BasicConverter} for a list of supported conversion 
types.
         * @param key The attribute name.
         * @return The attribute value, or <jk>null</jk> if the named attribute 
does not exist.
+        * @throws InvalidConversionException If the attribute value cannot be 
converted to the specified type.
         */
        public <T> T getAttr(Class<T> type, String key) {
-               return attrs == null ? null : 
ConverterUtils.toType(attrs.get(key), type);
+               return attrs == null ? null : 
BasicConverter.INSTANCE.to(attrs.get(key), type);
        }
 
        /**
diff --git 
a/juneau-bean/juneau-bean-html5/src/main/java/org/apache/juneau/bean/html5/HtmlElementContainer.java
 
b/juneau-bean/juneau-bean-html5/src/main/java/org/apache/juneau/bean/html5/HtmlElementContainer.java
index 6457f78e7e..fb857cdb60 100644
--- 
a/juneau-bean/juneau-bean-html5/src/main/java/org/apache/juneau/bean/html5/HtmlElementContainer.java
+++ 
b/juneau-bean/juneau-bean-html5/src/main/java/org/apache/juneau/bean/html5/HtmlElementContainer.java
@@ -20,9 +20,8 @@ import static org.apache.juneau.xml.annotation.XmlFormat.*;
 
 import java.util.*;
 
-import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.internal.*;
+import org.apache.juneau.commons.conversion.*;
 import org.apache.juneau.xml.annotation.*;
 
 /**
@@ -108,10 +107,10 @@ public class HtmlElementContainer extends HtmlElement {
         * @param type The class type of the node.
         * @param index The index of the node in the list of children.
         * @return The child node, or <jk>null</jk> if it doesn't exist.
-        * @throws InvalidDataConversionException If node is not the expected 
type.
+        * @throws InvalidConversionException If node is not the expected type.
         */
        public <T> T getChild(Class<T> type, int index) {
-               return (children == null || children.size() <= index || index < 
0 ? null : ConverterUtils.toType(children.get(index), type));
+               return (children == null || children.size() <= index || index < 
0 ? null : BasicConverter.INSTANCE.to(children.get(index), type));
        }
 
        /**
diff --git 
a/juneau-bean/juneau-bean-html5/src/main/java/org/apache/juneau/bean/html5/HtmlElementMixed.java
 
b/juneau-bean/juneau-bean-html5/src/main/java/org/apache/juneau/bean/html5/HtmlElementMixed.java
index ba372e5ff7..ae6ca34707 100644
--- 
a/juneau-bean/juneau-bean-html5/src/main/java/org/apache/juneau/bean/html5/HtmlElementMixed.java
+++ 
b/juneau-bean/juneau-bean-html5/src/main/java/org/apache/juneau/bean/html5/HtmlElementMixed.java
@@ -20,9 +20,8 @@ import static org.apache.juneau.xml.annotation.XmlFormat.*;
 
 import java.util.*;
 
-import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.internal.*;
+import org.apache.juneau.commons.conversion.*;
 import org.apache.juneau.xml.annotation.*;
 
 /**
@@ -114,10 +113,10 @@ public class HtmlElementMixed extends HtmlElement {
         * @param type The class type of the node.
         * @param index The index of the node in the list of children.
         * @return The child node, or <jk>null</jk> if it doesn't exist.
-        * @throws InvalidDataConversionException If node is not the expected 
type.
+        * @throws InvalidConversionException If node is not the expected type.
         */
        public <T> T getChild(Class<T> type, int index) {
-               return (children == null || children.size() <= index || index < 
0 ? null : ConverterUtils.toType(children.get(index), type));
+               return (children == null || children.size() <= index || index < 
0 ? null : BasicConverter.INSTANCE.to(children.get(index), type));
        }
 
        /**
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ConverterUtils.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ConverterUtils.java
index 72f4189cb9..5077cde3a8 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ConverterUtils.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ConverterUtils.java
@@ -22,141 +22,13 @@ import static 
org.apache.juneau.commons.utils.ThrowableUtils.*;
 
 import java.util.*;
 
-import org.apache.juneau.*;
 import org.apache.juneau.commons.collections.*;
+import org.apache.juneau.commons.conversion.BasicConverter;
 import org.apache.juneau.parser.*;
-import org.apache.juneau.swap.*;
 import org.apache.juneau.utils.*;
 
 /**
- * Utility class for efficiently converting objects between types.
- *
- * <p>
- * If the value isn't an instance of the specified type, then converts the 
value if possible.
- *
- * <p>
- * The following conversions are valid:
- * <table class='styled'>
- *     <tr><th>Convert to type</th><th>Valid input value 
types</th><th>Notes</th></tr>
- *     <tr>
- *             <td>
- *                     A class that is the normal type of a registered {@link 
ObjectSwap}.
- *             </td>
- *             <td>
- *                     A value whose class matches the transformed type of 
that registered {@link ObjectSwap}.
- *             </td>
- *             <td>&nbsp;</td>
- *     </tr>
- *     <tr>
- *             <td>
- *                     A class that is the transformed type of a registered 
{@link ObjectSwap}.
- *             </td>
- *             <td>
- *                     A value whose class matches the normal type of that 
registered {@link ObjectSwap}.
- *             </td>
- *             <td>&nbsp;</td>
- *     </tr>
- *     <tr>
- *             <td>
- *                     {@code Number} (e.g. {@code Integer}, {@code Short}, 
{@code Float},...)
- *                     <br><code>Number.<jsf>TYPE</jsf></code> (e.g. 
<code>Integer.<jsf>TYPE</jsf></code>,
- *                     <code>Short.<jsf>TYPE</jsf></code>, 
<code>Float.<jsf>TYPE</jsf></code>,...)
- *             </td>
- *             <td>
- *                     {@code Number}, {@code String}, <jk>null</jk>
- *             </td>
- *             <td>
- *                     For primitive {@code TYPES}, <jk>null</jk> returns the 
JVM default value for that type.
- *             </td>
- *     </tr>
- *     <tr>
- *             <td>
- *                     {@code Map} (e.g. {@code Map}, {@code HashMap}, {@code 
TreeMap}, {@code JsonMap})
- *             </td>
- *             <td>
- *                     {@code Map}
- *             </td>
- *             <td>
- *                     If {@code Map} is not constructible, an {@code JsonMap} 
is created.
- *             </td>
- *     </tr>
- *     <tr>
- *             <td>
- *                     <c>Collection</c> (e.g. <c>List</c>, <c>LinkedList</c>, 
<c>HashSet</c>, <c>JsonList</c>)
- *             </td>
- *             <td>
- *                     <c>Collection&lt;Object&gt;</c>
- *                     <br><c>Object[]</c>
- *             </td>
- *             <td>
- *                     If <c>Collection</c> is not constructible, a 
<c>JsonList</c> is created.
- *             </td>
- *     </tr>
- *     <tr>
- *             <td>
- *                     <c>X[]</c> (array of any type X)
- *             </td>
- *             <td>
- *                     <c>List&lt;X&gt;</c>
- *             </td>
- *             <td>&nbsp;</td>
- *     </tr>
- *     <tr>
- *             <td>
- *                     <c>X[][]</c> (multi-dimensional arrays)
- *             </td>
- *             <td>
- *                     <c>List&lt;List&lt;X&gt;&gt;</c>
- *                     <br><c>List&lt;X[]&gt;</c>
- *                     <br><c> List[]&lt;X&gt;</c>
- *             </td>
- *             <td>&nbsp;</td>
- *     </tr>
- *     <tr>
- *             <td>
- *                     <c>Enum</c>
- *             </td>
- *             <td>
- *                     <c>String</c>
- *             </td>
- *             <td>&nbsp;</td>
- *     </tr>
- *     <tr>
- *             <td>
- *                     Bean
- *             </td>
- *             <td>
- *                     <c>Map</c>
- *             </td>
- *             <td>&nbsp;</td>
- *     </tr>
- *     <tr>
- *             <td>
- *                     <c>String</c>
- *             </td>
- *             <td>
- *                     Anything
- *             </td>
- *             <td>
- *                     Arrays are converted to JSON arrays
- *             </td>
- *     </tr>
- *     <tr>
- *             <td>
- *                     Anything with one of the following methods:
- *                     <br><code><jk>public static</jk> T 
fromString(String)</code>
- *                     <br><code><jk>public static</jk> T 
valueOf(String)</code>
- *                     <br><code><jk>public</jk> T(String)</code>
- *             </td>
- *             <td>
- *                     <c>String</c>
- *             </td>
- *             <td>
- *                     <br>
- *             </td>
- *     </tr>
- * </table>
- *
+ * Utility class for common type conversions and building typed collections 
and maps.
  */
 public class ConverterUtils {
 
@@ -165,10 +37,6 @@ public class ConverterUtils {
         */
        private ConverterUtils() {}
 
-       // Session objects are usually not thread safe, but we're not using any 
feature
-       // of bean sessions that would cause thread safety issues.
-       private static final BeanSession session = BeanContext.DEFAULT_SESSION;
-
        /**
         * Converts an object to a Boolean.
         *
@@ -176,7 +44,7 @@ public class ConverterUtils {
         * @return The converted object.
         */
        public static Boolean toBoolean(Object o) {
-               return toType(o, Boolean.class);
+               return BasicConverter.INSTANCE.to(o, Boolean.class);
        }
 
        /**
@@ -186,7 +54,7 @@ public class ConverterUtils {
         * @return The converted object.
         */
        public static Integer toInteger(Object o) {
-               return toType(o, Integer.class);
+               return BasicConverter.INSTANCE.to(o, Integer.class);
        }
 
        /**
@@ -210,14 +78,17 @@ public class ConverterUtils {
        /**
         * Converts the specified object to the specified type.
         *
+        * <p>
+        * Uses the full {@link BeanContextConverter} to support bean-aware 
conversions such as
+        * {@link java.util.Map} to bean, bean to bean, and {@link 
org.apache.juneau.swap.ObjectSwap} transforms.
+        *
         * @param <T> The class type to convert the value to.
         * @param value The value to convert.
         * @param type The class type to convert the value to.
-        * @throws InvalidDataConversionException If the specified value cannot 
be converted to the specified type.
         * @return The converted value.
         */
        public static <T> T toType(Object value, Class<T> type) {
-               return session.convertToType(value, type);
+               return BeanContextConverter.INSTANCE.to(value, type);
        }
 
        /**
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swap/AutoNumberSwap.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swap/AutoNumberSwap.java
index 7eaa40118a..4d52dc0ddb 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swap/AutoNumberSwap.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swap/AutoNumberSwap.java
@@ -25,8 +25,8 @@ import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
+import org.apache.juneau.commons.conversion.*;
 import org.apache.juneau.commons.reflect.*;
-import org.apache.juneau.internal.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.serializer.*;
 
@@ -247,7 +247,7 @@ public class AutoNumberSwap<T> extends ObjectSwap<T,Number> 
{
                if (unswapType == null)
                        throw new ParseException("No unparse methodology found 
for object.");
                try {
-                       Object o2 = ConverterUtils.toType(o, unswapType);
+                       Object o2 = BasicConverter.INSTANCE.to(o, unswapType);
                        if (nn(unswapMethod))
                                return (T)unswapMethod.invoke(null, 
getMatchingArgs(unswapMethod.getParameterTypes(), session, o2));
                        if (nn(unswapConstructor))

Reply via email to