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> </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> </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<Object></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<X></c>
- * </td>
- * <td> </td>
- * </tr>
- * <tr>
- * <td>
- * <c>X[][]</c> (multi-dimensional arrays)
- * </td>
- * <td>
- * <c>List<List<X>></c>
- * <br><c>List<X[]></c>
- * <br><c> List[]<X></c>
- * </td>
- * <td> </td>
- * </tr>
- * <tr>
- * <td>
- * <c>Enum</c>
- * </td>
- * <td>
- * <c>String</c>
- * </td>
- * <td> </td>
- * </tr>
- * <tr>
- * <td>
- * Bean
- * </td>
- * <td>
- * <c>Map</c>
- * </td>
- * <td> </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))