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 7434e13dd6 Replace Mutaters with BasicConverter
7434e13dd6 is described below
commit 7434e13dd6b1053f55760f33c0f9a3b99e8048ff
Author: James Bognar <[email protected]>
AuthorDate: Thu Apr 2 15:47:16 2026 -0700
Replace Mutaters with BasicConverter
---
.../commons/conversion/CachingConverter.java | 42 +++++++++++++++++-----
.../commons/conversion/BasicConverter_Test.java | 9 ++++-
2 files changed, 42 insertions(+), 9 deletions(-)
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/CachingConverter.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/CachingConverter.java
index f524d775cf..06b94947a3 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/CachingConverter.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/CachingConverter.java
@@ -57,6 +57,30 @@ public abstract class CachingConverter implements Converter {
// Using this sentinel avoids re-invoking findConversion() for
unconvertable type pairs.
private static final Conversion<?,?> NO_CONVERSION = (in, memberOf,
session, args) -> null; // HTT: sentinel body is never invoked;
ConcurrentHashMap prohibits null values so we use this placeholder
+ /**
+ * Returns the JVM default value for a primitive type, or <jk>null</jk>
if the type is not primitive.
+ *
+ * <p>
+ * This is used to satisfy {@link #to} when the input is <jk>null</jk>
and the target type is a
+ * non-boxed primitive (e.g. {@code int.class}), where returning
<jk>null</jk> would be invalid.
+ *
+ * @param type The target type.
+ * @param <T> The target type.
+ * @return The JVM zero/false default, or <jk>null</jk> if {@code type}
is not a primitive.
+ */
+ @SuppressWarnings("unchecked")
+ private static <T> T primitiveDefault(Class<T> type) {
+ if (type == Integer.TYPE) return (T) Integer.valueOf(0);
+ if (type == Long.TYPE) return (T) Long.valueOf(0L);
+ if (type == Double.TYPE) return (T) Double.valueOf(0.0d);
+ if (type == Float.TYPE) return (T) Float.valueOf(0.0f);
+ if (type == Boolean.TYPE) return (T) Boolean.FALSE;
+ if (type == Short.TYPE) return (T) Short.valueOf((short)0);
+ if (type == Byte.TYPE) return (T) Byte.valueOf((byte)0);
+ if (type == Character.TYPE) return (T) Character.valueOf('\0');
+ return null; // HTT: no other primitive types exist in Java
+ }
+
// Two-level cache: input type -> output type -> conversion function
(or NO_CONVERSION sentinel).
private final Map<Class<?>, Map<Class<?>, Conversion<?,?>>> conversions
= new ConcurrentHashMap<>();
@@ -110,14 +134,15 @@ public abstract class CachingConverter implements
Converter {
* @param o The object to convert. Can be <jk>null</jk>.
* @param type The target type.
* @param <T> The target type.
- * @return The converted object, or <jk>null</jk> if the input is
<jk>null</jk>.
+ * @return The converted object, or the primitive zero-value if the
input is <jk>null</jk> and the target
+ * is a primitive type, or <jk>null</jk> otherwise.
* @throws InvalidConversionException If no conversion path exists from
the input type to the target type.
*/
@Override
@SuppressWarnings("unchecked")
public <T> T to(Object o, Class<T> type) {
if (o == null)
- return null;
+ return type.isPrimitive() ? primitiveDefault(type) :
null;
var inType = o.getClass();
if (inType == type)
return (T) o;
@@ -150,9 +175,9 @@ public abstract class CachingConverter implements Converter
{
@Override
@SuppressWarnings("unchecked")
public <T> T to(Object o, Type mainType, Type... args) {
- if (o == null)
- return null;
var rawType = (Class<T>) (mainType instanceof ParameterizedType
pt ? pt.getRawType() : (Class<?>) mainType);
+ if (o == null)
+ return rawType.isPrimitive() ?
primitiveDefault(rawType) : null;
var argClasses = Stream.of(args)
.map(t -> (Class<?>) (t instanceof ParameterizedType
pt2 ? pt2.getRawType() : t))
.toArray(Class[]::new);
@@ -175,14 +200,15 @@ public abstract class CachingConverter implements
Converter {
* @param session The converter session providing contextual objects,
or <jk>null</jk>.
* @param type The target type.
* @param <T> The target type.
- * @return The converted object, or <jk>null</jk> if the input is
<jk>null</jk>.
+ * @return The converted object, or the primitive zero-value if the
input is <jk>null</jk> and the target
+ * is a primitive type, or <jk>null</jk> otherwise.
* @throws InvalidConversionException If no conversion path exists from
the input type to the target type.
*/
@Override
@SuppressWarnings("unchecked")
public <T> T to(Object o, Object memberOf, ConverterSession session,
Class<T> type) {
if (o == null)
- return null;
+ return type.isPrimitive() ? primitiveDefault(type) :
null;
var inType = o.getClass();
if (inType == type)
return (T) o;
@@ -211,9 +237,9 @@ public abstract class CachingConverter implements Converter
{
@Override
@SuppressWarnings("unchecked")
public <T> T to(Object o, Object memberOf, ConverterSession session,
Type mainType, Type... args) {
- if (o == null)
- return null;
var rawType = (Class<T>) (mainType instanceof ParameterizedType
pt ? pt.getRawType() : (Class<?>) mainType);
+ if (o == null)
+ return rawType.isPrimitive() ?
primitiveDefault(rawType) : null;
var argClasses = Stream.of(args)
.map(t -> (Class<?>) (t instanceof ParameterizedType
pt2 ? pt2.getRawType() : t))
.toArray(Class[]::new);
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/conversion/BasicConverter_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/conversion/BasicConverter_Test.java
index 5ae2aede09..fc3a62993f 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/commons/conversion/BasicConverter_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/commons/conversion/BasicConverter_Test.java
@@ -753,7 +753,14 @@ class BasicConverter_Test extends TestBase {
assertNull(C.to(null, Integer.class));
assertNull(C.to(null, List.class));
assertNull(C.to(null, Map.class));
- assertNull(C.to(null, int.class));
+ assertEquals(0, (int) C.to(null, int.class));
+ assertEquals(0L, (long) C.to(null, long.class));
+ assertEquals(0.0d, (double) C.to(null, double.class));
+ assertEquals(0.0f, (float) C.to(null, float.class));
+ assertEquals(false, (boolean) C.to(null, boolean.class));
+ assertEquals((short)0, (short) C.to(null, short.class));
+ assertEquals((byte)0, (byte) C.to(null, byte.class));
+ assertEquals('\0', (char) C.to(null, char.class));
}
//====================================================================================================