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 51df205dd7 Replace Mutaters with BasicConverter
51df205dd7 is described below
commit 51df205dd7548dbb105bc66548df87a7c5ec5223
Author: James Bognar <[email protected]>
AuthorDate: Thu Apr 2 15:26:20 2026 -0700
Replace Mutaters with BasicConverter
---
.../juneau/commons/conversion/BasicConverter.java | 90 +++++++++++-----------
.../commons/conversion/CachingConverter.java | 30 +++++---
.../commons/conversion/ConfigurableConverter.java | 15 ++++
.../juneau/commons/conversion/Conversion.java | 4 +-
.../juneau/commons/conversion/Converter.java | 50 ++++++------
.../commons/conversion/ConverterSession.java | 76 ++++++++++++++++++
.../main/java/org/apache/juneau/BeanContext.java | 46 +++++++++++
.../main/java/org/apache/juneau/BeanSession.java | 22 +++++-
.../apache/juneau/utils/BeanContextConverter.java | 6 +-
.../commons/conversion/BasicConverter_Test.java | 6 +-
.../commons/conversion/CachingConverter_Test.java | 24 +++---
.../conversion/ConfigurableConverter_Test.java | 22 +++---
.../juneau/commons/conversion/Converter_Test.java | 12 +--
13 files changed, 285 insertions(+), 118 deletions(-)
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/BasicConverter.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/BasicConverter.java
index 49308a6f0e..fd6d50284f 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/BasicConverter.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/BasicConverter.java
@@ -181,7 +181,7 @@ public class BasicConverter extends CachingConverter {
if ((c = findSpecialConversion(inType, out)) != null) return c;
if (out.isAssignableFrom(inType) &&
!Collection.class.isAssignableFrom(out) && !Map.class.isAssignableFrom(out))
- return (in, memberOf, args) -> (O) in;
+ return (in, memberOf, session, args) -> (O) in;
if (Number.class.isAssignableFrom(out) && (c =
findNumberConversion(inType, out)) != null) return c;
@@ -224,31 +224,31 @@ public class BasicConverter extends CachingConverter {
}
private <I, O> Conversion<I, O> findNumberFromNumber(Class<O> outType) {
- if (outType == Integer.class) return (in, memberOf, args) ->
(O) Integer.valueOf(((Number) in).intValue());
- if (outType == Long.class) return (in, memberOf, args) -> (O)
Long.valueOf(((Number) in).longValue());
- if (outType == Short.class) return (in, memberOf, args) -> (O)
Short.valueOf(((Number) in).shortValue());
- if (outType == Float.class) return (in, memberOf, args) -> (O)
Float.valueOf(((Number) in).floatValue());
- if (outType == Double.class) return (in, memberOf, args) -> (O)
Double.valueOf(((Number) in).doubleValue());
- if (outType == Byte.class) return (in, memberOf, args) -> (O)
Byte.valueOf(((Number) in).byteValue());
- if (outType == AtomicInteger.class) return (in, memberOf, args)
-> (O) new AtomicInteger(((Number) in).intValue());
- if (outType == AtomicLong.class) return (in, memberOf, args) ->
(O) new AtomicLong(((Number) in).longValue());
+ if (outType == Integer.class) return (in, memberOf, session,
args) -> (O) Integer.valueOf(((Number) in).intValue());
+ if (outType == Long.class) return (in, memberOf, session, args)
-> (O) Long.valueOf(((Number) in).longValue());
+ if (outType == Short.class) return (in, memberOf, session,
args) -> (O) Short.valueOf(((Number) in).shortValue());
+ if (outType == Float.class) return (in, memberOf, session,
args) -> (O) Float.valueOf(((Number) in).floatValue());
+ if (outType == Double.class) return (in, memberOf, session,
args) -> (O) Double.valueOf(((Number) in).doubleValue());
+ if (outType == Byte.class) return (in, memberOf, session, args)
-> (O) Byte.valueOf(((Number) in).byteValue());
+ if (outType == AtomicInteger.class) return (in, memberOf,
session, args) -> (O) new AtomicInteger(((Number) in).intValue());
+ if (outType == AtomicLong.class) return (in, memberOf, session,
args) -> (O) new AtomicLong(((Number) in).longValue());
return null;
}
private <O> Conversion<Boolean, O> findNumberFromBoolean(Class<O>
outType) {
- if (outType == Integer.class) return (in, memberOf, args) ->
(O) Integer.valueOf(in.booleanValue() ? 1 : 0);
- if (outType == Long.class) return (in, memberOf, args) -> (O)
Long.valueOf(in.booleanValue() ? 1L : 0L);
- if (outType == Short.class) return (in, memberOf, args) -> (O)
Short.valueOf(in.booleanValue() ? (short) 1 : (short) 0);
- if (outType == Float.class) return (in, memberOf, args) -> (O)
Float.valueOf(in.booleanValue() ? 1f : 0f);
- if (outType == Double.class) return (in, memberOf, args) -> (O)
Double.valueOf(in.booleanValue() ? 1d : 0d);
- if (outType == Byte.class) return (in, memberOf, args) -> (O)
Byte.valueOf(in.booleanValue() ? (byte) 1 : (byte) 0);
- if (outType == AtomicInteger.class) return (in, memberOf, args)
-> (O) new AtomicInteger(in.booleanValue() ? 1 : 0);
- if (outType == AtomicLong.class) return (in, memberOf, args) ->
(O) new AtomicLong(in.booleanValue() ? 1L : 0L);
+ if (outType == Integer.class) return (in, memberOf, session,
args) -> (O) Integer.valueOf(in.booleanValue() ? 1 : 0);
+ if (outType == Long.class) return (in, memberOf, session, args)
-> (O) Long.valueOf(in.booleanValue() ? 1L : 0L);
+ if (outType == Short.class) return (in, memberOf, session,
args) -> (O) Short.valueOf(in.booleanValue() ? (short) 1 : (short) 0);
+ if (outType == Float.class) return (in, memberOf, session,
args) -> (O) Float.valueOf(in.booleanValue() ? 1f : 0f);
+ if (outType == Double.class) return (in, memberOf, session,
args) -> (O) Double.valueOf(in.booleanValue() ? 1d : 0d);
+ if (outType == Byte.class) return (in, memberOf, session, args)
-> (O) Byte.valueOf(in.booleanValue() ? (byte) 1 : (byte) 0);
+ if (outType == AtomicInteger.class) return (in, memberOf,
session, args) -> (O) new AtomicInteger(in.booleanValue() ? 1 : 0);
+ if (outType == AtomicLong.class) return (in, memberOf, session,
args) -> (O) new AtomicLong(in.booleanValue() ? 1L : 0L);
return null;
}
private <O> Conversion<CharSequence, O> findNumberFromString(Class<O>
outType) {
- return (in, memberOf, args) -> (O) parseNumber(in.toString(),
(Class<? extends Number>) outType);
+ return (in, memberOf, session, args) -> (O)
parseNumber(in.toString(), (Class<? extends Number>) outType);
}
//-----------------------------------------------------------------------------------------------------------------
@@ -257,7 +257,7 @@ public class BasicConverter extends CachingConverter {
private <I, O> Conversion<I, O> findBooleanConversion(Class<I> inType) {
if (Number.class.isAssignableFrom(inType))
- return (in, memberOf, args) -> (O)
Boolean.valueOf(((Number) in).intValue() != 0);
+ return (in, memberOf, session, args) -> (O)
Boolean.valueOf(((Number) in).intValue() != 0);
return null;
}
@@ -267,12 +267,12 @@ public class BasicConverter extends CachingConverter {
private <I, O> Conversion<I, O> findCharacterConversion(Class<I>
inType) {
if (CharSequence.class.isAssignableFrom(inType))
- return (in, memberOf, args) -> {
+ return (in, memberOf, session, args) -> {
var s = in.toString();
return s.length() == 1 ? (O)
Character.valueOf(s.charAt(0)) : null;
};
if (Number.class.isAssignableFrom(inType))
- return (in, memberOf, args) -> (O)
Character.valueOf((char) ((Number) in).intValue());
+ return (in, memberOf, session, args) -> (O)
Character.valueOf((char) ((Number) in).intValue());
return null;
}
@@ -282,17 +282,17 @@ public class BasicConverter extends CachingConverter {
private <I> Conversion<I, String> findToStringConversion(Class<I>
inType) {
if (inType.isArray()) {
- if (inType == int[].class) return (in, memberOf, args)
-> Arrays.toString((int[]) in);
- if (inType == long[].class) return (in, memberOf, args)
-> Arrays.toString((long[]) in);
- if (inType == double[].class) return (in, memberOf,
args) -> Arrays.toString((double[]) in);
- if (inType == float[].class) return (in, memberOf,
args) -> Arrays.toString((float[]) in);
- if (inType == boolean[].class) return (in, memberOf,
args) -> Arrays.toString((boolean[]) in);
- if (inType == byte[].class) return (in, memberOf, args)
-> Arrays.toString((byte[]) in);
- if (inType == short[].class) return (in, memberOf,
args) -> Arrays.toString((short[]) in);
- if (inType == char[].class) return (in, memberOf, args)
-> Arrays.toString((char[]) in);
- return (in, memberOf, args) ->
Arrays.deepToString((Object[]) in);
+ if (inType == int[].class) return (in, memberOf,
session, args) -> Arrays.toString((int[]) in);
+ if (inType == long[].class) return (in, memberOf,
session, args) -> Arrays.toString((long[]) in);
+ if (inType == double[].class) return (in, memberOf,
session, args) -> Arrays.toString((double[]) in);
+ if (inType == float[].class) return (in, memberOf,
session, args) -> Arrays.toString((float[]) in);
+ if (inType == boolean[].class) return (in, memberOf,
session, args) -> Arrays.toString((boolean[]) in);
+ if (inType == byte[].class) return (in, memberOf,
session, args) -> Arrays.toString((byte[]) in);
+ if (inType == short[].class) return (in, memberOf,
session, args) -> Arrays.toString((short[]) in);
+ if (inType == char[].class) return (in, memberOf,
session, args) -> Arrays.toString((char[]) in);
+ return (in, memberOf, session, args) ->
Arrays.deepToString((Object[]) in);
}
- return (in, memberOf, args) -> in.toString();
+ return (in, memberOf, session, args) -> in.toString();
}
//-----------------------------------------------------------------------------------------------------------------
@@ -301,7 +301,7 @@ public class BasicConverter extends CachingConverter {
private <I, O> Conversion<I, O> findEnumConversion(Class<I> inType,
Class<O> outType) {
if (CharSequence.class.isAssignableFrom(inType))
- return (in, memberOf, args) -> (O)
Enum.valueOf((Class<Enum>) outType, in.toString());
+ return (in, memberOf, session, args) -> (O)
Enum.valueOf((Class<Enum>) outType, in.toString());
return null;
}
@@ -311,7 +311,7 @@ public class BasicConverter extends CachingConverter {
private <I, O> Conversion<I, O> findCollectionConversion(Class<I>
inType, Class<O> outType) {
if (Collection.class.isAssignableFrom(inType) ||
inType.isArray()) {
- return (in, memberOf, args) -> {
+ return (in, memberOf, session, args) -> {
var elemType = args.length > 0 ? args[0] : null;
if (elemType == null && !inType.isArray() &&
outType.isAssignableFrom(inType))
return (O) in;
@@ -350,7 +350,7 @@ public class BasicConverter extends CachingConverter {
private <I, O> Conversion<I, O> findMapConversion(Class<I> inType,
Class<O> outType) {
if (Map.class.isAssignableFrom(inType)) {
- return (in, memberOf, args) -> {
+ return (in, memberOf, session, args) -> {
var keyType = args.length > 0 ? args[0] : null;
var valType = args.length > 1 ? args[1] : null;
if (keyType == null &&
outType.isAssignableFrom(inType))
@@ -393,7 +393,7 @@ public class BasicConverter extends CachingConverter {
&& !canConvert(inComponentType,
componentType))
return null;
}
- return (in, memberOf, args) -> {
+ return (in, memberOf, session, args) -> {
if (Collection.class.isAssignableFrom(inType)) {
var list = (Collection<?>) in;
var arr =
Array.newInstance(componentType, list.size());
@@ -418,13 +418,13 @@ public class BasicConverter extends CachingConverter {
private <I, O> Conversion<I, O> findSpecialConversion(Class<I> inType,
Class<O> outType) {
if (inType == String.class && outType == TimeZone.class)
- return (Conversion<I, O>) (Conversion<String,
TimeZone>) (in, memberOf, args) -> TimeZone.getTimeZone(in);
+ return (Conversion<I, O>) (Conversion<String,
TimeZone>) (in, memberOf, session, args) -> TimeZone.getTimeZone(in);
if (TimeZone.class.isAssignableFrom(inType) && outType ==
String.class)
- return (Conversion<I, O>) (Conversion<TimeZone,
String>) (in, memberOf, args) -> in.getID();
+ return (Conversion<I, O>) (Conversion<TimeZone,
String>) (in, memberOf, session, args) -> in.getID();
if (inType == String.class && outType == Locale.class)
- return (Conversion<I, O>) (Conversion<String, Locale>)
(in, memberOf, args) -> Locale.forLanguageTag(in.replace('_', '-'));
+ return (Conversion<I, O>) (Conversion<String, Locale>)
(in, memberOf, session, args) -> Locale.forLanguageTag(in.replace('_', '-'));
if (CharSequence.class.isAssignableFrom(inType) && outType ==
Boolean.class)
- return (in, memberOf, args) -> {
+ return (in, memberOf, session, args) -> {
var s = in.toString();
if (s.isEmpty() || "null".equals(s))
return null;
@@ -443,7 +443,7 @@ public class BasicConverter extends CachingConverter {
for (var name : FACTORY_METHOD_NAMES) {
var opt = findStaticMethod(ci, name, inType, outType);
if (opt.isPresent())
- return (in, memberOf, args) ->
opt.get().invoke(null, in);
+ return (in, memberOf, session, args) ->
opt.get().invoke(null, in);
}
// Walk the type hierarchy (superclasses then interfaces) so
that e.g. InputStreamReader
@@ -453,7 +453,7 @@ public class BasicConverter extends CachingConverter {
for (var prefix : new String[]{"from", "for", "parse"})
{
var opt = findStaticMethod(ci, prefix + inName,
inType, outType);
if (opt.isPresent())
- return (in, memberOf, args) ->
opt.get().invoke(null, in);
+ return (in, memberOf, session, args) ->
opt.get().invoke(null, in);
}
}
for (var iface : allInterfaces(inType)) {
@@ -461,7 +461,7 @@ public class BasicConverter extends CachingConverter {
for (var prefix : new String[]{"from", "for", "parse"})
{
var opt = findStaticMethod(ci, prefix + inName,
inType, outType);
if (opt.isPresent())
- return (in, memberOf, args) ->
opt.get().invoke(null, in);
+ return (in, memberOf, session, args) ->
opt.get().invoke(null, in);
}
}
@@ -510,7 +510,7 @@ public class BasicConverter extends CachingConverter {
);
if (opt.isPresent()) {
var ctor = opt.get();
- return (in, memberOf, args) ->
ctor.newInstance(memberOf, in);
+ return (in, memberOf, session, args) ->
ctor.newInstance(memberOf, in);
}
}
@@ -521,7 +521,7 @@ public class BasicConverter extends CachingConverter {
);
if (opt.isPresent()) {
var ctor = opt.get();
- return (in, memberOf, args) -> ctor.newInstance(in);
+ return (in, memberOf, session, args) ->
ctor.newInstance(in);
}
return null;
}
@@ -543,7 +543,7 @@ public class BasicConverter extends CachingConverter {
);
if (opt.isPresent()) {
var method = opt.get();
- return (in, memberOf, args) -> method.invoke(in);
+ return (in, memberOf, session, args) ->
method.invoke(in);
}
return null;
}
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 cdd37efa1c..f524d775cf 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
@@ -55,7 +55,7 @@ public abstract class CachingConverter implements Converter {
// Sentinel stored in the cache when findConversion() returns null.
// ConcurrentHashMap does not permit null values, so we cannot store
null directly.
// Using this sentinel avoids re-invoking findConversion() for
unconvertable type pairs.
- private static final Conversion<?,?> NO_CONVERSION = (in, memberOf,
args) -> null; // HTT: sentinel body is never invoked; ConcurrentHashMap
prohibits null values so we use this placeholder
+ 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
// Two-level cache: input type -> output type -> conversion function
(or NO_CONVERSION sentinel).
private final Map<Class<?>, Map<Class<?>, Conversion<?,?>>> conversions
= new ConcurrentHashMap<>();
@@ -124,7 +124,7 @@ public abstract class CachingConverter implements Converter
{
var fn = (Conversion<Object, T>) lookupConversion(inType, type);
if (fn == null)
throw new InvalidConversionException(inType, type);
- return fn.to(o, null);
+ return fn.to(o, null, (ConverterSession)null);
}
/**
@@ -160,15 +160,19 @@ public abstract class CachingConverter implements
Converter {
var fn = (Conversion<Object, T>) lookupConversion(inType,
rawType);
if (fn == null)
throw new InvalidConversionException(inType, rawType);
- return fn.to(o, null, argClasses);
+ return fn.to(o, null, (ConverterSession)null, argClasses);
}
/**
- * Converts the specified object to the specified type, passing the
outer instance for
- * non-static inner class construction.
+ * Converts the specified object to the specified type, using the given
outer instance and converter session.
+ *
+ * <p>
+ * The session is forwarded to the cached {@link Conversion} function
so conversion lambdas can access
+ * contextual objects such as {@link java.util.TimeZone} or {@link
java.util.Locale}.
*
* @param o The object to convert. Can be <jk>null</jk>.
* @param memberOf The outer instance for non-static inner class
construction, or <jk>null</jk>.
+ * @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>.
@@ -176,7 +180,7 @@ public abstract class CachingConverter implements Converter
{
*/
@Override
@SuppressWarnings("unchecked")
- public <T> T to(Object o, Object memberOf, Class<T> type) {
+ public <T> T to(Object o, Object memberOf, ConverterSession session,
Class<T> type) {
if (o == null)
return null;
var inType = o.getClass();
@@ -185,15 +189,19 @@ public abstract class CachingConverter implements
Converter {
var fn = (Conversion<Object, T>) lookupConversion(inType, type);
if (fn == null)
throw new InvalidConversionException(inType, type);
- return fn.to(o, memberOf);
+ return fn.to(o, memberOf, session);
}
/**
- * Converts the specified object to the specified parameterized type,
passing the outer instance for
- * non-static inner class construction.
+ * Converts the specified object to the specified parameterized type,
using the given outer instance and converter session.
+ *
+ * <p>
+ * The session is forwarded to the cached {@link Conversion} function
so conversion lambdas can access
+ * contextual objects such as {@link java.util.TimeZone} or {@link
java.util.Locale}.
*
* @param o The object to convert. Can be <jk>null</jk>.
* @param memberOf The outer instance for non-static inner class
construction, or <jk>null</jk>.
+ * @param session The converter session providing contextual objects,
or <jk>null</jk>.
* @param mainType The target type. May be a {@link Class} or {@link
ParameterizedType}.
* @param args The type arguments of the target type (e.g. element type
for collections).
* @param <T> The target type.
@@ -202,7 +210,7 @@ public abstract class CachingConverter implements Converter
{
*/
@Override
@SuppressWarnings("unchecked")
- public <T> T to(Object o, Object memberOf, Type mainType, Type... args)
{
+ 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);
@@ -213,6 +221,6 @@ public abstract class CachingConverter implements Converter
{
var fn = (Conversion<Object, T>) lookupConversion(inType,
rawType);
if (fn == null)
throw new InvalidConversionException(inType, rawType);
- return fn.to(o, memberOf, argClasses);
+ return fn.to(o, memberOf, session, argClasses);
}
}
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/ConfigurableConverter.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/ConfigurableConverter.java
index 243014ac36..6cfddb85a4 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/ConfigurableConverter.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/ConfigurableConverter.java
@@ -86,6 +86,21 @@ public class ConfigurableConverter extends BasicConverter {
return this;
}
+ /**
+ * Returns <jk>true</jk> if a custom conversion has been explicitly
registered for the specified type pair.
+ *
+ * <p>
+ * This only checks the user-registered conversions, not the built-in
{@link BasicConverter} reflection logic.
+ *
+ * @param inType The input type class.
+ * @param outType The output type class.
+ * @return <jk>true</jk> if a custom conversion exists for the
specified type pair.
+ */
+ public boolean hasCustomConversion(Class<?> inType, Class<?> outType) {
+ var inner = registered.get(inType);
+ return inner != null && inner.containsKey(outType);
+ }
+
@Override
protected <I, O> Conversion<I, O> findConversion(Class<I> inType,
Class<O> outType) {
var inner = registered.get(inType);
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/Conversion.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/Conversion.java
index b1480aff73..ae37854402 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/Conversion.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/Conversion.java
@@ -41,8 +41,10 @@ public interface Conversion<I, O> {
*
* @param in The input object.
* @param memberOf The outer instance for non-static inner class
construction, or <jk>null</jk>.
+ * @param session The converter session providing contextual objects
such as {@link java.util.TimeZone} or
+ * {@link java.util.Locale}, or <jk>null</jk> if no session is
available.
* @param args Optional type arguments for parameterized output types
(e.g. element type for collections).
* @return The converted object.
*/
- O to(I in, Object memberOf, Class<?>... args);
+ O to(I in, Object memberOf, ConverterSession session, Class<?>... args);
}
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/Converter.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/Converter.java
index 7db0a003f2..0a0d958340 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/Converter.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/Converter.java
@@ -54,25 +54,6 @@ public interface Converter {
*/
<T> T to(Object o, Class<T> type);
- /**
- * Converts the specified object to the specified type, using the given
outer instance for
- * non-static inner class construction.
- *
- * <p>
- * Returns <jk>null</jk> only when the input object is <jk>null</jk>.
- * Throws {@link InvalidConversionException} when no conversion path
exists.
- *
- * @param o The object to convert.
- * @param memberOf The outer instance for non-static inner class
construction, or <jk>null</jk>.
- * @param type The type to convert to.
- * @param <T> The type to convert to.
- * @return The converted object, or <jk>null</jk> if the input is
<jk>null</jk>.
- * @throws InvalidConversionException If no conversion path exists from
the input type to the target type.
- */
- default <T> T to(Object o, Object memberOf, Class<T> type) {
- return to(o, type);
- }
-
/**
* Converts the specified object to the specified parameterized type.
*
@@ -103,22 +84,43 @@ public interface Converter {
<T> T to(Object o, Type mainType, Type...args);
/**
- * Converts the specified object to the specified parameterized type,
using the given outer instance for
- * non-static inner class construction.
+ * Converts the specified object to the specified type, using the given
outer instance and converter session.
*
* <p>
- * Returns <jk>null</jk> only when the input object is <jk>null</jk>.
- * Throws {@link InvalidConversionException} when no conversion path
exists.
+ * The default implementation ignores both {@code memberOf} and {@code
session} and delegates to
+ * {@link #to(Object, Class)}.
+ * Override in subclasses that wish to thread these into {@link
Conversion#to(Object, Object, ConverterSession, Class[])}.
+ *
+ * @param o The object to convert.
+ * @param memberOf The outer instance for non-static inner class
construction, or <jk>null</jk>.
+ * @param session The converter session providing contextual objects,
or <jk>null</jk>.
+ * @param type The type to convert to.
+ * @param <T> The type to convert to.
+ * @return The converted object, or <jk>null</jk> if the input is
<jk>null</jk>.
+ * @throws InvalidConversionException If no conversion path exists from
the input type to the target type.
+ */
+ default <T> T to(Object o, Object memberOf, ConverterSession session,
Class<T> type) {
+ return to(o, type);
+ }
+
+ /**
+ * Converts the specified object to the specified parameterized type,
using the given outer instance and converter session.
+ *
+ * <p>
+ * The default implementation ignores both {@code memberOf} and {@code
session} and delegates to
+ * {@link #to(Object, Type, Type[])}.
+ * Override in subclasses that wish to thread these into {@link
Conversion#to(Object, Object, ConverterSession, Class[])}.
*
* @param o The object to convert.
* @param memberOf The outer instance for non-static inner class
construction, or <jk>null</jk>.
+ * @param session The converter session providing contextual objects,
or <jk>null</jk>.
* @param mainType The main type to convert to.
* @param args The type parameters of the main type.
* @param <T> The type to convert to.
* @return The converted object, or <jk>null</jk> if the input is
<jk>null</jk>.
* @throws InvalidConversionException If no conversion path exists from
the input type to the target type.
*/
- default <T> T to(Object o, Object memberOf, Type mainType, Type...args)
{
+ default <T> T to(Object o, Object memberOf, ConverterSession session,
Type mainType, Type...args) {
return to(o, mainType, args);
}
}
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/ConverterSession.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/ConverterSession.java
new file mode 100644
index 0000000000..d9884ddd3a
--- /dev/null
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/ConverterSession.java
@@ -0,0 +1,76 @@
+/*
+ * 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.conversion;
+
+import java.util.*;
+
+/**
+ * Provides contextual objects to {@link Conversion} functions at call time.
+ *
+ * <p>
+ * A {@code ConverterSession} is passed through the {@link
Conversion#to(Object, Object, ConverterSession, Class[])}
+ * method and allows conversion lambdas to retrieve session-scoped objects
such as a {@link java.util.TimeZone},
+ * {@link java.util.Locale}, or media type without requiring those objects to
be captured in the lambda closure.
+ *
+ * <p>
+ * Implementations look up contextual objects by type (and optionally by
name). If no matching object is
+ * registered for the requested type the method returns {@link
Optional#empty()}.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bjava'>
+ * <jc>// A conversion that uses the session's TimeZone.</jc>
+ * BeanContext <jv>bc</jv> = BeanContext
+ * .<jsm>create</jsm>()
+ * .addConverter(String.<jk>class</jk>, Calendar.<jk>class</jk>,
(<jv>in</jv>, <jv>memberOf</jv>, <jv>session</jv>, <jv>args</jv>) -> {
+ * var <jv>tz</jv> =
<jv>session</jv>.get(TimeZone.<jk>class</jk>).orElse(TimeZone.<jsm>getDefault</jsm>());
+ * <jc>// ... parse string using tz ...</jc>
+ * })
+ * .build();
+ * </p>
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ * <li class='jc'>{@link Conversion}
+ * <li class='jc'>{@link Converter}
+ * </ul>
+ */
+public interface ConverterSession {
+
+ /**
+ * Returns a contextual object of the specified type, or {@link
Optional#empty()} if none is registered.
+ *
+ * @param <T> The object type.
+ * @param c The object type to look up.
+ * @return The contextual object wrapped in an {@link Optional}, or
{@link Optional#empty()} if not available.
+ */
+ <T> Optional<T> get(Class<T> c);
+
+ /**
+ * Returns a named contextual object of the specified type, or {@link
Optional#empty()} if none is registered.
+ *
+ * <p>
+ * The default implementation ignores the name and delegates to {@link
#get(Class)}.
+ * Override this method when multiple objects of the same type need to
be distinguished by name.
+ *
+ * @param <T> The object type.
+ * @param name The object name, or <jk>null</jk> to match any.
+ * @param c The object type to look up.
+ * @return The contextual object wrapped in an {@link Optional}, or
{@link Optional#empty()} if not available.
+ */
+ default <T> Optional<T> get(String name, Class<T> c) {
+ return get(c);
+ }
+}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
index a867940270..ba4ba41dba 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
@@ -33,6 +33,7 @@ import java.util.stream.*;
import org.apache.juneau.annotation.*;
import org.apache.juneau.commons.collections.*;
+import org.apache.juneau.commons.conversion.*;
import org.apache.juneau.commons.function.*;
import org.apache.juneau.commons.reflect.*;
import org.apache.juneau.commons.reflect.Visibility;
@@ -257,6 +258,7 @@ public class BeanContext extends Context {
private Set<ClassInfo> notBeanClasses;
private Set<String> notBeanPackages;
+ private ConfigurableConverter converter;
/**
* Constructor.
@@ -312,6 +314,7 @@ public class BeanContext extends Context {
beansRequireDefaultConstructor =
copyFrom.beansRequireDefaultConstructor;
beansRequireSerializable =
copyFrom.beansRequireSerializable;
beansRequireSettersForGetters =
copyFrom.beansRequireSettersForGetters;
+ converter = copyFrom.converter;
disableBeansRequireSomeProperties = !
copyFrom.beansRequireSomeProperties;
disableIgnoreMissingSetters = !
copyFrom.ignoreMissingSetters;
disableIgnoreTransientFields = !
copyFrom.ignoreTransientFields;
@@ -351,6 +354,7 @@ public class BeanContext extends Context {
beansRequireDefaultConstructor =
copyFrom.beansRequireDefaultConstructor;
beansRequireSerializable =
copyFrom.beansRequireSerializable;
beansRequireSettersForGetters =
copyFrom.beansRequireSettersForGetters;
+ converter = copyFrom.converter;
disableBeansRequireSomeProperties =
copyFrom.disableBeansRequireSomeProperties;
disableIgnoreMissingSetters =
copyFrom.disableIgnoreMissingSetters;
disableIgnoreTransientFields =
copyFrom.disableIgnoreTransientFields;
@@ -398,6 +402,37 @@ public class BeanContext extends Context {
return this;
}
+ /**
+ * Registers a custom type conversion on this context.
+ *
+ * <p>
+ * User-registered conversions take priority over built-in type
dispatch in
+ * {@link BeanSession#convertToMemberType(Object, Object,
ClassMeta)}, but are checked after
+ * {@link ObjectSwap} processing.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bjava'>
+ * <jc>// Register a custom String-to-MyBean
conversion.</jc>
+ * BeanContext <jv>bc</jv> = BeanContext
+ * .<jsm>create</jsm>()
+ * .addConverter(String.<jk>class</jk>,
MyBean.<jk>class</jk>, (<jv>in</jv>, <jv>memberOf</jv>, <jv>session</jv>,
<jv>args</jv>) -> MyBean.fromString(<jv>in</jv>))
+ * .build();
+ * </p>
+ *
+ * @param <I> The input type.
+ * @param <O> The output type.
+ * @param inType The input type class.
+ * @param outType The output type class.
+ * @param conversion The conversion function.
+ * @return This object.
+ */
+ public <I, O> Builder addConverter(Class<I> inType, Class<O>
outType, Conversion<I, O> conversion) {
+ if (converter == null)
+ converter = new ConfigurableConverter();
+ converter.add(inType, outType, conversion);
+ return this;
+ }
+
/**
* Minimum bean class visibility.
*
@@ -2226,6 +2261,7 @@ public class BeanContext extends Context {
beanMethodVisibility,
beanFieldVisibility,
beanDictionary,
+ converter != null ?
System.identityHashCode(converter) : 0,
swaps,
notBeanClasses,
notBeanPackages,
@@ -3628,6 +3664,7 @@ public class BeanContext extends Context {
private final NullableSupplier<WriterSerializer> beanToStringSerializer;
private final BeanRegistry beanRegistry;
private final BeanSession defaultSession;
+ private final ConfigurableConverter converter;
private final boolean beanMapPutReturnsOldValue;
private final boolean beansRequireDefaultConstructor;
private final boolean beansRequireSerializable;
@@ -3685,6 +3722,7 @@ public class BeanContext extends Context {
beansRequireSerializable = builder.beansRequireSerializable;
beansRequireSettersForGetters =
builder.beansRequireSettersForGetters;
beansRequireSomeProperties = !
builder.disableBeansRequireSomeProperties;
+ converter = builder.converter;
findFluentSetters = builder.findFluentSetters;
hashKey = builder.hashKey();
ignoreInvocationExceptionsOnGetters =
builder.ignoreInvocationExceptionsOnGetters;
@@ -3807,6 +3845,14 @@ public class BeanContext extends Context {
*/
public final Visibility getBeanFieldVisibility() { return
beanFieldVisibility; }
+ /**
+ * Returns the custom converter registered on this context, or
<jk>null</jk> if none.
+ *
+ * @see BeanContext.Builder#addConverter(Class, Class, Conversion)
+ * @return The custom converter, or <jk>null</jk> if no custom
conversions have been registered.
+ */
+ public final ConfigurableConverter getConverter() { return converter; }
+
/**
* Returns the {@link BeanMeta} class for the specified class.
*
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
index 4aafb9e8cf..b8d141a09d 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
@@ -36,6 +36,7 @@ import java.util.logging.*;
import org.apache.juneau.annotation.*;
import org.apache.juneau.collections.*;
import org.apache.juneau.commons.collections.FluentMap;
+import org.apache.juneau.commons.conversion.*;
import org.apache.juneau.commons.lang.*;
import org.apache.juneau.commons.reflect.*;
import org.apache.juneau.commons.time.*;
@@ -58,7 +59,7 @@ import org.apache.juneau.utils.*;
"java:S115", // Constants use UPPER_snakeCase naming convention
"java:S1452" // Wildcard required - ClassMeta<?>, ObjectSwap<?,?>,
etc. for bean metadata
})
-public class BeanSession extends ContextSession {
+public class BeanSession extends ContextSession implements ConverterSession {
// Property name constants
private static final String PROP_locale = "locale";
@@ -266,8 +267,11 @@ public class BeanSession extends ContextSession {
return 1;
}
- private static boolean hasMutater(ClassMeta<?> from, ClassMeta<?> to) {
- return to.hasMutaterFrom(from) || from.hasMutaterTo(to);
+ private boolean hasMutater(ClassMeta<?> from, ClassMeta<?> to) {
+ if (to.hasMutaterFrom(from) || from.hasMutaterTo(to))
+ return true;
+ var c = ctx.getConverter();
+ return c != null && c.hasCustomConversion(from.inner(),
to.inner());
}
private static final boolean isNullOrEmpty(Object o) {
@@ -292,6 +296,14 @@ public class BeanSession extends ContextSession {
timeZone = opt(builder.timeZone).orElse(builder.timeZone);
}
+ @Override /* ConverterSession */
+ public <T> Optional<T> get(Class<T> c) {
+ if (c == TimeZone.class) return opt(c.cast(timeZone));
+ if (c == Locale.class) return opt(c.cast(locale));
+ if (c == MediaType.class) return opt(c.cast(mediaType));
+ return opte();
+ }
+
/**
* Logs a warning message.
*
@@ -1220,6 +1232,10 @@ public class BeanSession extends ContextSession {
return (T)swap.swap(this, value);
}
+ var ctxConverter = ctx.getConverter();
+ if (ctxConverter != null &&
ctxConverter.hasCustomConversion(from.inner(), tc))
+ return ctxConverter.to(value, outer, this, tc);
+
if (to.isCharSequence() &&
(from.isDateOrCalendarOrTemporal() || from.isDuration()))
return (T) Iso8601Utils.format(value, from,
getTimeZone());
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/BeanContextConverter.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/BeanContextConverter.java
index ea70f714af..81e0fd6704 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/BeanContextConverter.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/BeanContextConverter.java
@@ -126,13 +126,14 @@ public class BeanContextConverter implements Converter {
*
* @param o The object to convert.
* @param memberOf The outer instance for non-static inner class
construction, or <jk>null</jk>.
+ * @param session The converter session, or <jk>null</jk>.
* @param type The target class type.
* @param <T> The target type to convert to.
* @return The converted object, or <jk>null</jk> if the input object
is <jk>null</jk>.
* @throws InvalidDataConversionException If the object cannot be
converted to the specified type.
*/
@Override
- public <T> T to(Object o, Object memberOf, Class<T> type) {
+ public <T> T to(Object o, Object memberOf, ConverterSession session,
Class<T> type) {
return
BeanContext.DEFAULT_SESSION.convertToMemberType(memberOf, o, type);
}
@@ -142,6 +143,7 @@ public class BeanContextConverter implements Converter {
*
* @param o The object to convert.
* @param memberOf The outer instance for non-static inner class
construction, or <jk>null</jk>.
+ * @param session The converter session, or <jk>null</jk>.
* @param mainType The main type to convert to.
* @param args The type parameters of the main type.
* @param <T> The target type to convert to.
@@ -150,7 +152,7 @@ public class BeanContextConverter implements Converter {
*/
@SuppressWarnings("unchecked")
@Override
- public <T> T to(Object o, Object memberOf, Type mainType, Type... args)
{
+ public <T> T to(Object o, Object memberOf, ConverterSession session,
Type mainType, Type... args) {
var rawType = (Class<T>) (mainType instanceof ParameterizedType
pt ? pt.getRawType() : (Class<?>) mainType);
return
BeanContext.DEFAULT_SESSION.convertToMemberType(memberOf, o, rawType);
}
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 cdf2875c02..5ae2aede09 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
@@ -781,9 +781,9 @@ class BasicConverter_Test extends TestBase {
}
@Test void p01_innerClassConstructorWithMemberOf() {
- // to(o, memberOf, Class) routes through the inner-class path
in findConstructorConversion;
+ // to(o, memberOf, session, Class) routes through the
inner-class path in findConstructorConversion;
// memberOf (this) is passed as the synthetic outer-instance
parameter.
- var x = C.to("hello", this, P01_Inner.class);
+ var x = C.to("hello", this, (ConverterSession)null,
P01_Inner.class);
assertEquals("hello", x.value);
}
@@ -791,7 +791,7 @@ class BasicConverter_Test extends TestBase {
// The inner-class branch is entered (P02 has an enclosing
class) but the 2-param ctor
// (BasicConverter_Test, String) does not exist — falls through
to the 1-param check which also
// fails → InvalidConversionException.
- assertThrows(InvalidConversionException.class, () ->
C.to("hello", this, P02_InnerNoMatch.class));
+ assertThrows(InvalidConversionException.class, () ->
C.to("hello", this, (ConverterSession)null, P02_InnerNoMatch.class));
}
//====================================================================================================
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/conversion/CachingConverter_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/conversion/CachingConverter_Test.java
index 7501573dac..814ce48612 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/commons/conversion/CachingConverter_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/commons/conversion/CachingConverter_Test.java
@@ -107,40 +107,40 @@ class CachingConverter_Test extends TestBase {
}
//====================================================================================================
- // c - to(Object, Object, Class)
+ // c - to(Object, Object, ConverterSession, Class)
//====================================================================================================
@Test void c01_toMemberOfNullInput() {
- assertNull(C.to(null, "ignored", String.class));
+ assertNull(C.to(null, "ignored", (ConverterSession)null,
String.class));
}
@Test void c02_toMemberOfSameType() {
var s = "hello";
- assertSame(s, C.to(s, null, String.class));
+ assertSame(s, C.to(s, null, (ConverterSession)null,
String.class));
}
@Test void c03_toMemberOfConversion() {
- assertEquals("42", C.to(42, null, String.class));
+ assertEquals("42", C.to(42, null, (ConverterSession)null,
String.class));
}
@Test void c04_toMemberOfNoConversion() {
- assertThrows(InvalidConversionException.class, () -> C.to(new
StringBuilder("x"), null, java.net.URI.class));
+ assertThrows(InvalidConversionException.class, () -> C.to(new
StringBuilder("x"), null, (ConverterSession)null, java.net.URI.class));
}
//====================================================================================================
- // d - to(Object, Object, Type, Type...)
+ // d - to(Object, Object, ConverterSession, Type, Type...)
//====================================================================================================
// Sentinel used as the memberOf argument to avoid null-vs-Type
overload ambiguity.
private static final Object D_MEMBER_OF = new Object();
@Test void d01_toMemberOfTypeNullInput() {
- assertNull(C.to(null, D_MEMBER_OF, (Type) String.class));
+ assertNull(C.to(null, D_MEMBER_OF, (ConverterSession)null,
(Type) String.class));
}
@Test void d02_toMemberOfTypePlainClass() {
// mainType is a plain Class (false branch of ParameterizedType
ternary)
- assertEquals("42", C.to(42, D_MEMBER_OF, (Type) String.class));
+ assertEquals("42", C.to(42, D_MEMBER_OF,
(ConverterSession)null, (Type) String.class));
}
@SuppressWarnings("unused")
@@ -156,25 +156,25 @@ class CachingConverter_Test extends TestBase {
@Test void d03_toMemberOfTypeWithParameterizedType() {
// mainType is a ParameterizedType (true branch of ternary);
raw type List is extracted
- var result = C.to(List.of("a", "b"), D_MEMBER_OF,
D03_LIST_TYPE);
+ var result = C.to(List.of("a", "b"), D_MEMBER_OF,
(ConverterSession)null, D03_LIST_TYPE);
assertNotNull(result);
assertInstanceOf(List.class, result);
}
@Test void d04_toMemberOfTypeWithPlainClassArg() {
// args contains a plain Class (false branch of arg ternary)
- var result = C.to(List.of("1", "2"), D_MEMBER_OF, (Type)
List.class, (Type) Integer.class);
+ var result = C.to(List.of("1", "2"), D_MEMBER_OF,
(ConverterSession)null, (Type) List.class, (Type) Integer.class);
assertEquals(List.of(1, 2), result);
}
@Test void d05_toMemberOfTypeWithParameterizedTypeArg() {
// args contains a ParameterizedType (true branch of arg
ternary); raw type List is extracted
- var result = C.to(List.of(List.of("a", "b")), D_MEMBER_OF,
(Type) List.class, LIST_ARG_TYPE);
+ var result = C.to(List.of(List.of("a", "b")), D_MEMBER_OF,
(ConverterSession)null, (Type) List.class, LIST_ARG_TYPE);
assertNotNull(result);
assertInstanceOf(List.class, result);
}
@Test void d06_toMemberOfTypeNoConversion() {
- assertThrows(InvalidConversionException.class, () -> C.to(new
StringBuilder("x"), D_MEMBER_OF, (Type) java.net.URI.class));
+ assertThrows(InvalidConversionException.class, () -> C.to(new
StringBuilder("x"), D_MEMBER_OF, (ConverterSession)null, (Type)
java.net.URI.class));
}
}
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/conversion/ConfigurableConverter_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/conversion/ConfigurableConverter_Test.java
index 5933c12b0d..d3106f6d4c 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/commons/conversion/ConfigurableConverter_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/commons/conversion/ConfigurableConverter_Test.java
@@ -42,7 +42,7 @@ public class ConfigurableConverter_Test {
@Test void a01_registeredConversionIsUsed() {
var c = new ConfigurableConverter()
- .add(String.class, A01_Value.class, (in, memberOf,
args) -> new A01_Value(in));
+ .add(String.class, A01_Value.class, (in, memberOf,
session, args) -> new A01_Value(in));
var result = c.to("hello", A01_Value.class);
assertNotNull(result);
assertEquals("hello", result.raw);
@@ -51,7 +51,7 @@ public class ConfigurableConverter_Test {
@Test void a02_registeredConversionTakesPriorityOverBuiltIn() {
// Integer→String has a built-in conversion; register a custom
one that wraps with brackets
var c = new ConfigurableConverter()
- .add(Integer.class, String.class, (in, memberOf, args)
-> "[" + in + "]");
+ .add(Integer.class, String.class, (in, memberOf,
session, args) -> "[" + in + "]");
assertEquals("[42]", c.to(42, String.class));
}
@@ -63,13 +63,13 @@ public class ConfigurableConverter_Test {
@Test void a04_nullInputReturnsNull() {
var c = new ConfigurableConverter()
- .add(String.class, A01_Value.class, (in, memberOf,
args) -> new A01_Value(in));
+ .add(String.class, A01_Value.class, (in, memberOf,
session, args) -> new A01_Value(in));
assertNull(c.to(null, A01_Value.class));
}
@Test void a05_canConvertReturnsTrueForRegisteredType() {
var c = new ConfigurableConverter()
- .add(String.class, A01_Value.class, (in, memberOf,
args) -> new A01_Value(in));
+ .add(String.class, A01_Value.class, (in, memberOf,
session, args) -> new A01_Value(in));
assertTrue(c.canConvert(String.class, A01_Value.class));
}
@@ -85,8 +85,8 @@ public class ConfigurableConverter_Test {
@Test void a08_multipleRegistrationsOnSameConverter() {
var c = new ConfigurableConverter()
- .add(String.class, A01_Value.class, (in, memberOf,
args) -> new A01_Value(in))
- .add(Integer.class, A01_Value.class, (in, memberOf,
args) -> new A01_Value(String.valueOf(in)));
+ .add(String.class, A01_Value.class, (in, memberOf,
session, args) -> new A01_Value(in))
+ .add(Integer.class, A01_Value.class, (in, memberOf,
session, args) -> new A01_Value(String.valueOf(in)));
assertEquals("hello", c.to("hello", A01_Value.class).raw);
assertEquals("42", c.to(42, A01_Value.class).raw);
}
@@ -101,7 +101,7 @@ public class ConfigurableConverter_Test {
@Test void a09_registrationDoesNotAffectOtherInstances() {
var c1 = new ConfigurableConverter()
- .add(String.class, A09_Value.class, (in, memberOf,
args) -> new A09_Value(in));
+ .add(String.class, A09_Value.class, (in, memberOf,
session, args) -> new A09_Value(in));
var c2 = new ConfigurableConverter();
assertNotNull(c1.to("x", A09_Value.class));
assertFalse(c2.canConvert(String.class, A09_Value.class));
@@ -116,8 +116,8 @@ public class ConfigurableConverter_Test {
var memberOf = new Object();
var captured = new AtomicReference<Object>();
var c = new ConfigurableConverter()
- .add(String.class, Integer.class, (in, m, args) -> {
captured.set(m); return Integer.parseInt(in); });
- c.to("42", memberOf, Integer.class);
+ .add(String.class, Integer.class, (in, m, session,
args) -> { captured.set(m); return Integer.parseInt(in); });
+ c.to("42", memberOf, (ConverterSession)null, Integer.class);
assertSame(memberOf, captured.get());
}
@@ -144,7 +144,7 @@ public class ConfigurableConverter_Test {
pool.submit(() -> {
try {
latch.await();
- c.add(String.class, C01_Value.class,
(in, m, args) -> new C01_Value(in.toUpperCase()));
+ c.add(String.class, C01_Value.class,
(in, m, session, args) -> new C01_Value(in.toUpperCase()));
} catch (Exception e) {
errors.incrementAndGet();
}
@@ -161,7 +161,7 @@ public class ConfigurableConverter_Test {
@Test void c02_concurrentConvertsAreThreadSafe() throws Exception {
var c = new ConfigurableConverter()
- .add(String.class, Integer.class, (in, m, args) ->
Integer.parseInt(in) * 2);
+ .add(String.class, Integer.class, (in, m, session,
args) -> Integer.parseInt(in) * 2);
var threads = 32;
var latch = new CountDownLatch(1);
var errors = new AtomicInteger(0);
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/conversion/Converter_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/conversion/Converter_Test.java
index ddb072a68e..ff7036d098 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/commons/conversion/Converter_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/commons/conversion/Converter_Test.java
@@ -51,14 +51,14 @@ class Converter_Test extends TestBase {
@Override public <T> T to(Object o, Type mainType, Type...
args) { return BasicConverter.INSTANCE.to(o, mainType, args); }
};
- @Test void b01_defaultToMemberOfClass() {
- // default to(o, memberOf, Class) ignores memberOf and
delegates to to(o, Class)
- assertEquals(Integer.valueOf(42), B_STUB.to("42", new Object(),
Integer.class));
+ @Test void b01_defaultToSessionClass() {
+ // default to(o, memberOf, session, Class) ignores memberOf and
session and delegates to to(o, Class)
+ assertEquals(Integer.valueOf(42), B_STUB.to("42", new Object(),
(ConverterSession)null, Integer.class));
}
- @Test void b02_defaultToMemberOfType() {
- // default to(o, memberOf, Type, Type...) ignores memberOf and
delegates to to(o, Type, Type...)
- var result = B_STUB.to(List.of("1", "2"), new Object(), (Type)
List.class, new Type[]{Integer.class});
+ @Test void b02_defaultToSessionType() {
+ // default to(o, memberOf, session, Type, Type...) ignores
memberOf and session and delegates to to(o, Type, Type...)
+ var result = B_STUB.to(List.of("1", "2"), new Object(),
(ConverterSession)null, (Type) List.class, new Type[]{Integer.class});
assertEquals(List.of(1, 2), result);
}
}