aboutsummaryrefslogtreecommitdiff
path: root/velocity-engine-core/src/main/java/org/apache/velocity/util
diff options
context:
space:
mode:
authorClaude Brisson <cbrisson@apache.org>2019-12-03 16:57:12 +0000
committerClaude Brisson <cbrisson@apache.org>2019-12-03 16:57:12 +0000
commit21e80403e251d2816fc7f074a8540ccc0820021e (patch)
tree56871e894121f20feb92357fe2222331fc36e8b8 /velocity-engine-core/src/main/java/org/apache/velocity/util
parent9771388936aade4d3269acd97eae87266572e7b6 (diff)
downloadapache-velocity-engine-21e80403e251d2816fc7f074a8540ccc0820021e.tar.gz
[core] Added implicit conversions from/to BigInteger and BigDecimal
git-svn-id: https://svn.apache.org/repos/asf/velocity/engine/trunk@1870761 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'velocity-engine-core/src/main/java/org/apache/velocity/util')
-rw-r--r--velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/Converter.java1
-rw-r--r--velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/TypeConversionHandlerImpl.java587
-rw-r--r--velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectImpl.java15
3 files changed, 340 insertions, 263 deletions
diff --git a/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/Converter.java b/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/Converter.java
index 37e2fa98..276d0bd2 100644
--- a/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/Converter.java
+++ b/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/Converter.java
@@ -27,6 +27,7 @@ package org.apache.velocity.util.introspection;
* @version $Id$
*/
+@FunctionalInterface
public interface Converter<T>
{
/**
diff --git a/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/TypeConversionHandlerImpl.java b/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/TypeConversionHandlerImpl.java
index 9ee2c61d..e5bed092 100644
--- a/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/TypeConversionHandlerImpl.java
+++ b/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/TypeConversionHandlerImpl.java
@@ -24,9 +24,12 @@ import org.apache.commons.lang3.reflect.TypeUtils;
import org.apache.commons.lang3.tuple.Pair;
import java.lang.reflect.Type;
+import java.math.BigDecimal;
+import java.math.BigInteger;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
+import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -57,18 +60,6 @@ public class TypeConversionHandlerImpl implements TypeConversionHandler
static Converter cacheMiss;
/**
- * min/max byte/short/int values as long
- */
- static final long minByte = Byte.MIN_VALUE, maxByte = Byte.MAX_VALUE,
- minShort = Short.MIN_VALUE, maxShort = Short.MAX_VALUE,
- minInt = Integer.MIN_VALUE, maxInt = Integer.MAX_VALUE;
-
- /**
- * min/max long values as double
- */
- static final double minLong = Long.MIN_VALUE, maxLong = Long.MAX_VALUE;
-
- /**
* a converters cache map, initialized with the standard narrowing and string parsing conversions.
*/
Map<Pair<String, String>, Converter> converterCacheMap;
@@ -86,41 +77,53 @@ public class TypeConversionHandlerImpl implements TypeConversionHandler
static final String SHORT_CLASS = "java.lang.Short";
static final String INTEGER_CLASS = "java.lang.Integer";
static final String LONG_CLASS = "java.lang.Long";
+ static final String BIG_INTEGER_CLASS = "java.math.BigInteger";
static final String FLOAT_CLASS = "java.lang.Float";
static final String DOUBLE_CLASS = "java.lang.Double";
+ static final String BIG_DECIMAL_CLASS = "java.math.BigDecimal";
static final String NUMBER_CLASS = "java.lang.Number";
static final String CHARACTER_CLASS = "java.lang.Character";
static final String STRING_CLASS = "java.lang.String";
static final String LOCALE_CLASS = "java.util.Locale";
+ /*
+ * Bounds checking helper
+ */
+
+ static boolean checkBounds(Number n, double min, double max)
+ {
+ double d = n.doubleValue();
+ if (d < min || d > max)
+ {
+ throw new NumberFormatException("value out of range: " + n);
+ }
+ return true;
+ }
+
static
{
standardConverterMap = new HashMap<>();
- cacheMiss = new Converter<Object>()
- {
- @Override
- public Object convert(Object o)
- {
- return o;
- }
- };
+ cacheMiss = o -> o;
+
+ /*
+ * Conversions towards boolean
+ */
/* number -> boolean */
- Converter<Boolean> numberToBool = new Converter<Boolean>()
- {
- @Override
- public Boolean convert(Object o)
- {
- return o == null ? null : ((Number) o).intValue() != 0;
- }
- };
+
+ Converter<Boolean> numberToBool = o -> Optional.ofNullable((Number)o).map(n -> Double.compare(n.doubleValue(), 0.0) != 0).orElse(null);
+ Converter<Boolean> bigIntegerToBool = o -> Optional.ofNullable((BigInteger)o).map(bi -> bi.signum() != 0).orElse(null);
+ Converter<Boolean> bigDecimalToBool = o -> Optional.ofNullable((BigDecimal)o).map(bi -> bi.signum() != 0).orElse(null);
+
standardConverterMap.put(Pair.of(BOOLEAN_CLASS, BYTE_CLASS), numberToBool);
standardConverterMap.put(Pair.of(BOOLEAN_CLASS, SHORT_CLASS), numberToBool);
standardConverterMap.put(Pair.of(BOOLEAN_CLASS, INTEGER_CLASS), numberToBool);
standardConverterMap.put(Pair.of(BOOLEAN_CLASS, LONG_CLASS), numberToBool);
+ standardConverterMap.put(Pair.of(BOOLEAN_CLASS, BIG_INTEGER_CLASS), bigIntegerToBool);
standardConverterMap.put(Pair.of(BOOLEAN_CLASS, FLOAT_CLASS), numberToBool);
standardConverterMap.put(Pair.of(BOOLEAN_CLASS, DOUBLE_CLASS), numberToBool);
+ standardConverterMap.put(Pair.of(BOOLEAN_CLASS, BIG_DECIMAL_CLASS), bigDecimalToBool);
standardConverterMap.put(Pair.of(BOOLEAN_CLASS, NUMBER_CLASS), numberToBool);
standardConverterMap.put(Pair.of(BOOLEAN_CLASS, BYTE_TYPE), numberToBool);
standardConverterMap.put(Pair.of(BOOLEAN_CLASS, SHORT_TYPE), numberToBool);
@@ -131,9 +134,11 @@ public class TypeConversionHandlerImpl implements TypeConversionHandler
standardConverterMap.put(Pair.of(BOOLEAN_TYPE, BYTE_CLASS), numberToBool);
standardConverterMap.put(Pair.of(BOOLEAN_TYPE, SHORT_CLASS), numberToBool);
standardConverterMap.put(Pair.of(BOOLEAN_TYPE, INTEGER_CLASS), numberToBool);
+ standardConverterMap.put(Pair.of(BOOLEAN_TYPE, BIG_INTEGER_CLASS), bigIntegerToBool);
standardConverterMap.put(Pair.of(BOOLEAN_TYPE, LONG_CLASS), numberToBool);
standardConverterMap.put(Pair.of(BOOLEAN_TYPE, FLOAT_CLASS), numberToBool);
standardConverterMap.put(Pair.of(BOOLEAN_TYPE, DOUBLE_CLASS), numberToBool);
+ standardConverterMap.put(Pair.of(BOOLEAN_TYPE, BIG_DECIMAL_CLASS), bigDecimalToBool);
standardConverterMap.put(Pair.of(BOOLEAN_TYPE, NUMBER_CLASS), numberToBool);
standardConverterMap.put(Pair.of(BOOLEAN_TYPE, BYTE_TYPE), numberToBool);
standardConverterMap.put(Pair.of(BOOLEAN_TYPE, SHORT_TYPE), numberToBool);
@@ -143,51 +148,47 @@ public class TypeConversionHandlerImpl implements TypeConversionHandler
standardConverterMap.put(Pair.of(BOOLEAN_TYPE, DOUBLE_TYPE), numberToBool);
/* character -> boolean */
- Converter<Boolean> charToBoolean = new Converter<Boolean>()
- {
- @Override
- public Boolean convert(Object o)
- {
- return o == null ? null : (Character) o != 0;
- }
- };
+
+ Converter<Boolean> charToBoolean = o -> Optional.ofNullable((Character)o).map(c -> c != 0).orElse(null);
+
standardConverterMap.put(Pair.of(BOOLEAN_CLASS, CHARACTER_CLASS), charToBoolean);
standardConverterMap.put(Pair.of(BOOLEAN_CLASS, CHARACTER_TYPE), charToBoolean);
standardConverterMap.put(Pair.of(BOOLEAN_TYPE, CHARACTER_CLASS), charToBoolean);
standardConverterMap.put(Pair.of(BOOLEAN_TYPE, CHARACTER_TYPE), charToBoolean);
/* string -> boolean */
- Converter<Boolean> stringToBoolean = new Converter<Boolean>()
- {
- @Override
- public Boolean convert(Object o)
- {
- return Boolean.valueOf(String.valueOf(o));
- }
- };
+
+ Converter<Boolean> stringToBoolean = o -> Boolean.valueOf(String.valueOf(o));
+
standardConverterMap.put(Pair.of(BOOLEAN_CLASS, STRING_CLASS), stringToBoolean);
standardConverterMap.put(Pair.of(BOOLEAN_TYPE, STRING_CLASS), stringToBoolean);
+ /*
+ * Conversions towards byte
+ */
+
/* narrowing towards byte */
- Converter<Byte> narrowingToByte = new Converter<Byte>()
- {
- @Override
- public Byte convert(Object o)
- {
- if (o == null) return null;
- long l = ((Number)o).longValue();
- if (l < minByte || l > maxByte)
- {
- throw new NumberFormatException("value out of range for byte type: " + l);
- }
- return ((Number) o).byteValue();
- }
- };
+
+ Converter<Byte> narrowingToByte = o -> Optional.ofNullable((Number)o)
+ .filter(n -> checkBounds(n, Byte.MIN_VALUE, Byte.MAX_VALUE))
+ .map(Number::byteValue)
+ .orElse(null);
+
+ Converter<Byte> narrowingBigIntegerToByte = o -> Optional.ofNullable((BigInteger)o)
+ .map(BigInteger::byteValueExact)
+ .orElse(null);
+
+ Converter<Byte> narrowingBigDecimalToByte = o -> Optional.ofNullable((BigDecimal)o)
+ .map(BigDecimal::byteValueExact)
+ .orElse(null);
+
standardConverterMap.put(Pair.of(BYTE_CLASS, SHORT_CLASS), narrowingToByte);
standardConverterMap.put(Pair.of(BYTE_CLASS, INTEGER_CLASS), narrowingToByte);
standardConverterMap.put(Pair.of(BYTE_CLASS, LONG_CLASS), narrowingToByte);
+ standardConverterMap.put(Pair.of(BYTE_CLASS, BIG_INTEGER_CLASS), narrowingBigIntegerToByte);
standardConverterMap.put(Pair.of(BYTE_CLASS, FLOAT_CLASS), narrowingToByte);
standardConverterMap.put(Pair.of(BYTE_CLASS, DOUBLE_CLASS), narrowingToByte);
+ standardConverterMap.put(Pair.of(BYTE_CLASS, BIG_DECIMAL_CLASS), narrowingBigDecimalToByte);
standardConverterMap.put(Pair.of(BYTE_CLASS, NUMBER_CLASS), narrowingToByte);
standardConverterMap.put(Pair.of(BYTE_CLASS, SHORT_TYPE), narrowingToByte);
standardConverterMap.put(Pair.of(BYTE_CLASS, INTEGER_TYPE), narrowingToByte);
@@ -197,8 +198,10 @@ public class TypeConversionHandlerImpl implements TypeConversionHandler
standardConverterMap.put(Pair.of(BYTE_TYPE, SHORT_CLASS), narrowingToByte);
standardConverterMap.put(Pair.of(BYTE_TYPE, INTEGER_CLASS), narrowingToByte);
standardConverterMap.put(Pair.of(BYTE_TYPE, LONG_CLASS), narrowingToByte);
+ standardConverterMap.put(Pair.of(BYTE_TYPE, BIG_INTEGER_CLASS), narrowingBigIntegerToByte);
standardConverterMap.put(Pair.of(BYTE_TYPE, FLOAT_CLASS), narrowingToByte);
standardConverterMap.put(Pair.of(BYTE_TYPE, DOUBLE_CLASS), narrowingToByte);
+ standardConverterMap.put(Pair.of(BYTE_TYPE, BIG_DECIMAL_CLASS), narrowingBigDecimalToByte);
standardConverterMap.put(Pair.of(BYTE_TYPE, NUMBER_CLASS), narrowingToByte);
standardConverterMap.put(Pair.of(BYTE_TYPE, SHORT_TYPE), narrowingToByte);
standardConverterMap.put(Pair.of(BYTE_TYPE, INTEGER_TYPE), narrowingToByte);
@@ -207,36 +210,37 @@ public class TypeConversionHandlerImpl implements TypeConversionHandler
standardConverterMap.put(Pair.of(BYTE_TYPE, DOUBLE_TYPE), narrowingToByte);
/* string to byte */
- Converter<Byte> stringToByte = new Converter<Byte>()
- {
- @Override
- public Byte convert(Object o)
- {
- return Byte.valueOf(String.valueOf(o));
- }
- };
+
+ Converter<Byte> stringToByte = o -> Byte.valueOf(String.valueOf(o));
+
standardConverterMap.put(Pair.of(BYTE_CLASS, STRING_CLASS), stringToByte);
standardConverterMap.put(Pair.of(BYTE_TYPE, STRING_CLASS), stringToByte);
+ /*
+ * Conversions towards short
+ */
+
/* narrowing towards short */
- Converter<Short> narrowingToShort = new Converter<Short>()
- {
- @Override
- public Short convert(Object o)
- {
- if (o == null) return null;
- long l = ((Number)o).longValue();
- if (l < minShort || l > maxShort)
- {
- throw new NumberFormatException("value out of range for short type: " + l);
- }
- return ((Number) o).shortValue();
- }
- };
+
+ Converter<Short> narrowingToShort = o -> Optional.ofNullable((Number)o)
+ .filter(n -> checkBounds(n, Short.MIN_VALUE, Short.MAX_VALUE))
+ .map(Number::shortValue)
+ .orElse(null);
+
+ Converter<Short> narrowingBigIntegerToShort = o -> Optional.ofNullable((BigInteger)o)
+ .map(BigInteger::shortValueExact)
+ .orElse(null);
+
+ Converter<Short> narrowingBigDecimalToShort = o -> Optional.ofNullable((BigDecimal)o)
+ .map(BigDecimal::shortValueExact)
+ .orElse(null);
+
standardConverterMap.put(Pair.of(SHORT_CLASS, INTEGER_CLASS), narrowingToShort);
standardConverterMap.put(Pair.of(SHORT_CLASS, LONG_CLASS), narrowingToShort);
+ standardConverterMap.put(Pair.of(SHORT_CLASS, BIG_INTEGER_CLASS), narrowingBigIntegerToShort);
standardConverterMap.put(Pair.of(SHORT_CLASS, FLOAT_CLASS), narrowingToShort);
standardConverterMap.put(Pair.of(SHORT_CLASS, DOUBLE_CLASS), narrowingToShort);
+ standardConverterMap.put(Pair.of(SHORT_CLASS, BIG_DECIMAL_CLASS), narrowingBigDecimalToShort);
standardConverterMap.put(Pair.of(SHORT_CLASS, NUMBER_CLASS), narrowingToShort);
standardConverterMap.put(Pair.of(SHORT_CLASS, INTEGER_TYPE), narrowingToShort);
standardConverterMap.put(Pair.of(SHORT_CLASS, LONG_TYPE), narrowingToShort);
@@ -244,194 +248,244 @@ public class TypeConversionHandlerImpl implements TypeConversionHandler
standardConverterMap.put(Pair.of(SHORT_CLASS, DOUBLE_TYPE), narrowingToShort);
standardConverterMap.put(Pair.of(SHORT_TYPE, INTEGER_CLASS), narrowingToShort);
standardConverterMap.put(Pair.of(SHORT_TYPE, LONG_CLASS), narrowingToShort);
+ standardConverterMap.put(Pair.of(SHORT_TYPE, BIG_INTEGER_CLASS), narrowingBigIntegerToShort);
standardConverterMap.put(Pair.of(SHORT_TYPE, FLOAT_CLASS), narrowingToShort);
standardConverterMap.put(Pair.of(SHORT_TYPE, DOUBLE_CLASS), narrowingToShort);
+ standardConverterMap.put(Pair.of(SHORT_TYPE, BIG_DECIMAL_CLASS), narrowingBigDecimalToShort);
standardConverterMap.put(Pair.of(SHORT_TYPE, NUMBER_CLASS), narrowingToShort);
standardConverterMap.put(Pair.of(SHORT_TYPE, INTEGER_TYPE), narrowingToShort);
standardConverterMap.put(Pair.of(SHORT_TYPE, LONG_TYPE), narrowingToShort);
standardConverterMap.put(Pair.of(SHORT_TYPE, FLOAT_TYPE), narrowingToShort);
standardConverterMap.put(Pair.of(SHORT_TYPE, DOUBLE_TYPE), narrowingToShort);
+ /* widening towards short */
+
+ Converter<Short> wideningToShort = o -> Optional.ofNullable((Number)o)
+ .map(Number::shortValue)
+ .orElse(null);
+
+ standardConverterMap.put(Pair.of(SHORT_CLASS, BYTE_CLASS), wideningToShort);
+ standardConverterMap.put(Pair.of(SHORT_CLASS, BYTE_TYPE), wideningToShort);
+
/* string to short */
- Converter<Short> stringToShort = new Converter<Short>()
- {
- @Override
- public Short convert(Object o)
- {
- return Short.valueOf(String.valueOf(o));
- }
- };
+
+ Converter<Short> stringToShort = o -> Short.valueOf(String.valueOf(o));
+
standardConverterMap.put(Pair.of(SHORT_CLASS, STRING_CLASS), stringToShort);
standardConverterMap.put(Pair.of(SHORT_TYPE, STRING_CLASS), stringToShort);
+ /*
+ * Conversions towards int
+ */
+
/* narrowing towards int */
- Converter<Integer> narrowingToInteger = new Converter<Integer>()
- {
- @Override
- public Integer convert(Object o)
- {
- if (o == null) return null;
- long l = ((Number)o).longValue();
- if (l < minInt || l > maxInt)
- {
- throw new NumberFormatException("value out of range for integer type: " + l);
- }
- return ((Number) o).intValue();
- }
- };
+
+ Converter<Integer> narrowingToInteger = o -> Optional.ofNullable((Number)o)
+ .filter(n -> checkBounds(n, Integer.MIN_VALUE, Integer.MAX_VALUE))
+ .map(Number::intValue)
+ .orElse(null);
+
+ Converter<Integer> narrowingBigIntegerToInteger = o -> Optional.ofNullable((BigInteger)o)
+ .map(BigInteger::intValueExact)
+ .orElse(null);
+
+ Converter<Integer> narrowingBigDecimalToInteger = o -> Optional.ofNullable((BigDecimal)o)
+ .map(BigDecimal::intValueExact)
+ .orElse(null);
+
standardConverterMap.put(Pair.of(INTEGER_CLASS, LONG_CLASS), narrowingToInteger);
+ standardConverterMap.put(Pair.of(INTEGER_CLASS, BIG_INTEGER_CLASS), narrowingBigIntegerToInteger);
standardConverterMap.put(Pair.of(INTEGER_CLASS, FLOAT_CLASS), narrowingToInteger);
standardConverterMap.put(Pair.of(INTEGER_CLASS, DOUBLE_CLASS), narrowingToInteger);
+ standardConverterMap.put(Pair.of(INTEGER_CLASS, BIG_DECIMAL_CLASS), narrowingBigDecimalToInteger);
standardConverterMap.put(Pair.of(INTEGER_CLASS, NUMBER_CLASS), narrowingToInteger);
standardConverterMap.put(Pair.of(INTEGER_CLASS, LONG_TYPE), narrowingToInteger);
standardConverterMap.put(Pair.of(INTEGER_CLASS, FLOAT_TYPE), narrowingToInteger);
standardConverterMap.put(Pair.of(INTEGER_CLASS, DOUBLE_TYPE), narrowingToInteger);
standardConverterMap.put(Pair.of(INTEGER_TYPE, LONG_CLASS), narrowingToInteger);
+ standardConverterMap.put(Pair.of(INTEGER_TYPE, BIG_INTEGER_CLASS), narrowingBigIntegerToInteger);
standardConverterMap.put(Pair.of(INTEGER_TYPE, FLOAT_CLASS), narrowingToInteger);
standardConverterMap.put(Pair.of(INTEGER_TYPE, DOUBLE_CLASS), narrowingToInteger);
+ standardConverterMap.put(Pair.of(INTEGER_TYPE, BIG_DECIMAL_CLASS), narrowingBigDecimalToInteger);
standardConverterMap.put(Pair.of(INTEGER_TYPE, NUMBER_CLASS), narrowingToInteger);
standardConverterMap.put(Pair.of(INTEGER_TYPE, LONG_TYPE), narrowingToInteger);
standardConverterMap.put(Pair.of(INTEGER_TYPE, FLOAT_TYPE), narrowingToInteger);
standardConverterMap.put(Pair.of(INTEGER_TYPE, DOUBLE_TYPE), narrowingToInteger);
- /* widening towards Integer */
- Converter<Integer> wideningToInteger = new Converter<Integer>()
- {
- @Override
- public Integer convert(Object o)
- {
- if (o == null) return null;
- return ((Number) o).intValue();
- }
- };
+ /* widening towards int */
+
+ Converter<Integer> wideningToInteger = o -> Optional.ofNullable((Number)o)
+ .map(Number::intValue)
+ .orElse(null);
+
+ standardConverterMap.put(Pair.of(INTEGER_CLASS, BYTE_CLASS), wideningToInteger);
standardConverterMap.put(Pair.of(INTEGER_CLASS, SHORT_CLASS), wideningToInteger);
+ standardConverterMap.put(Pair.of(INTEGER_CLASS, BYTE_TYPE), wideningToInteger);
standardConverterMap.put(Pair.of(INTEGER_CLASS, SHORT_TYPE), wideningToInteger);
/* string to int */
- Converter<Integer> stringToInteger = new Converter<Integer>()
- {
- @Override
- public Integer convert(Object o)
- {
- return Integer.valueOf(String.valueOf(o));
- }
- };
+
+ Converter<Integer> stringToInteger = o -> Integer.valueOf(String.valueOf(o));
+
standardConverterMap.put(Pair.of(INTEGER_CLASS, STRING_CLASS), stringToInteger);
standardConverterMap.put(Pair.of(INTEGER_TYPE, STRING_CLASS), stringToInteger);
+ /*
+ * Conversions towards long
+ */
+
/* narrowing towards long */
- Converter<Long> narrowingToLong = new Converter<Long>()
- {
- @Override
- public Long convert(Object o)
- {
- if (o == null) return null;
- double d = ((Number)o).doubleValue();
- if (d < minLong || d > maxLong)
- {
- throw new NumberFormatException("value out of range for long type: " + d);
- }
- return ((Number) o).longValue();
- }
- };
+
+ Converter<Long> narrowingToLong = o -> Optional.ofNullable((Number)o)
+ .filter(n -> checkBounds(n, Long.MIN_VALUE, Long.MAX_VALUE))
+ .map(Number::longValue)
+ .orElse(null);
+
+ Converter<Long> narrowingBigIntegerToLong = o -> Optional.ofNullable((BigInteger)o)
+ .map(BigInteger::longValueExact)
+ .orElse(null);
+
+ Converter<Long> narrowingBigDecimalToLong = o -> Optional.ofNullable((BigDecimal)o)
+ .map(BigDecimal::longValueExact)
+ .orElse(null);
+
+ standardConverterMap.put(Pair.of(LONG_CLASS, BIG_INTEGER_CLASS), narrowingBigIntegerToLong);
standardConverterMap.put(Pair.of(LONG_CLASS, FLOAT_CLASS), narrowingToLong);
standardConverterMap.put(Pair.of(LONG_CLASS, DOUBLE_CLASS), narrowingToLong);
+ standardConverterMap.put(Pair.of(LONG_CLASS, BIG_DECIMAL_CLASS), narrowingBigDecimalToLong);
standardConverterMap.put(Pair.of(LONG_CLASS, NUMBER_CLASS), narrowingToLong);
standardConverterMap.put(Pair.of(LONG_CLASS, FLOAT_TYPE), narrowingToLong);
standardConverterMap.put(Pair.of(LONG_CLASS, DOUBLE_TYPE), narrowingToLong);
+ standardConverterMap.put(Pair.of(LONG_TYPE, BIG_INTEGER_CLASS), narrowingBigIntegerToLong);
standardConverterMap.put(Pair.of(LONG_TYPE, FLOAT_CLASS), narrowingToLong);
standardConverterMap.put(Pair.of(LONG_TYPE, DOUBLE_CLASS), narrowingToLong);
+ standardConverterMap.put(Pair.of(LONG_TYPE, BIG_DECIMAL_CLASS), narrowingBigDecimalToLong);
standardConverterMap.put(Pair.of(LONG_TYPE, NUMBER_CLASS), narrowingToLong);
standardConverterMap.put(Pair.of(LONG_TYPE, FLOAT_TYPE), narrowingToLong);
standardConverterMap.put(Pair.of(LONG_TYPE, DOUBLE_TYPE), narrowingToLong);
- /* widening towards Long */
- Converter<Long> wideningToLong = new Converter<Long>()
- {
- @Override
- public Long convert(Object o)
- {
- if (o == null) return null;
- return ((Number) o).longValue();
- }
- };
+ /* widening towards long */
+
+ Converter<Long> wideningToLong = o -> Optional.ofNullable((Number)o)
+ .map(Number::longValue)
+ .orElse(null);
+
+ standardConverterMap.put(Pair.of(LONG_CLASS, BYTE_CLASS), wideningToLong);
standardConverterMap.put(Pair.of(LONG_CLASS, SHORT_CLASS), wideningToLong);
standardConverterMap.put(Pair.of(LONG_CLASS, INTEGER_CLASS), wideningToLong);
+ standardConverterMap.put(Pair.of(LONG_CLASS, BYTE_TYPE), wideningToLong);
standardConverterMap.put(Pair.of(LONG_CLASS, SHORT_TYPE), wideningToLong);
standardConverterMap.put(Pair.of(LONG_CLASS, INTEGER_TYPE), wideningToLong);
/* string to long */
- Converter<Long> stringToLong = new Converter<Long>()
- {
- @Override
- public Long convert(Object o)
- {
- return Long.valueOf(String.valueOf(o));
- }
- };
+
+ Converter<Long> stringToLong = o -> Long.valueOf(String.valueOf(o));
+
standardConverterMap.put(Pair.of(LONG_CLASS, STRING_CLASS), stringToLong);
standardConverterMap.put(Pair.of(LONG_TYPE, STRING_CLASS), stringToLong);
+ /*
+ * Conversions towards BigInteger
+ */
+
+ /* exact types towards BigInteger */
+
+ Converter<BigInteger> toBigInteger = o -> Optional.ofNullable((Number)o)
+ .map(n -> BigInteger.valueOf(n.longValue()))
+ .orElse(null);
+
+ standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, BYTE_CLASS), toBigInteger);
+ standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, SHORT_CLASS), toBigInteger);
+ standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, INTEGER_CLASS), toBigInteger);
+ standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, LONG_CLASS), toBigInteger);
+ standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, BYTE_TYPE), toBigInteger);
+ standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, SHORT_TYPE), toBigInteger);
+ standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, INTEGER_TYPE), toBigInteger);
+ standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, LONG_TYPE), toBigInteger);
+
+ /* approximate types towards BigInteger */
+
+ /* It makes no sense trying to convert from float or double towards BigInteger
+ if we do care about precision loss..
+ */
+
+ Converter<BigInteger> bigDecimalToBigInteger = o -> Optional.ofNullable((BigDecimal)o)
+ .map(BigDecimal::toBigIntegerExact)
+ .orElse(null);
+
+ standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, BIG_DECIMAL_CLASS), bigDecimalToBigInteger);
+
+ /* string to BigInteger */
+
+ Converter<BigInteger> stringToBigInteger = o -> Optional.ofNullable(o)
+ .map(s -> new BigInteger(String.valueOf(s)))
+ .orElse(null);
+
+ standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, STRING_CLASS), stringToBigInteger);
+
+ /*
+ * Conversions towards float
+ */
+
+ Converter<Float> toFloat = o -> Optional.ofNullable((Number)o)
+ .map(Number::floatValue)
+ .orElse(null);
+
/* narrowing towards float */
- Converter<Float> narrowingToFloat = new Converter<Float>()
- {
- @Override
- public Float convert(Object o)
- {
- return o == null ? null : ((Number) o).floatValue();
- }
- };
- standardConverterMap.put(Pair.of(FLOAT_CLASS, DOUBLE_CLASS), narrowingToFloat);
- standardConverterMap.put(Pair.of(FLOAT_CLASS, NUMBER_CLASS), narrowingToFloat);
- standardConverterMap.put(Pair.of(FLOAT_CLASS, DOUBLE_TYPE), narrowingToFloat);
- standardConverterMap.put(Pair.of(FLOAT_TYPE, DOUBLE_CLASS), narrowingToFloat);
- standardConverterMap.put(Pair.of(FLOAT_TYPE, NUMBER_CLASS), narrowingToFloat);
- standardConverterMap.put(Pair.of(FLOAT_TYPE, DOUBLE_TYPE), narrowingToFloat);
-
- /* exact towards Float */
- Converter<Float> toFloat = new Converter<Float>()
- {
- @Override
- public Float convert(Object o)
- {
- if (o == null) return null;
- return ((Number) o).floatValue();
- }
- };
+
+ standardConverterMap.put(Pair.of(FLOAT_CLASS, BIG_INTEGER_CLASS), toFloat);
+ standardConverterMap.put(Pair.of(FLOAT_CLASS, DOUBLE_CLASS), toFloat);
+ standardConverterMap.put(Pair.of(FLOAT_CLASS, BIG_DECIMAL_CLASS), toFloat);
+ standardConverterMap.put(Pair.of(FLOAT_CLASS, NUMBER_CLASS), toFloat);
+ standardConverterMap.put(Pair.of(FLOAT_CLASS, DOUBLE_TYPE), toFloat);
+ standardConverterMap.put(Pair.of(FLOAT_TYPE, BIG_INTEGER_CLASS), toFloat);
+ standardConverterMap.put(Pair.of(FLOAT_TYPE, DOUBLE_CLASS), toFloat);
+ standardConverterMap.put(Pair.of(FLOAT_TYPE, BIG_DECIMAL_CLASS), toFloat);
+ standardConverterMap.put(Pair.of(FLOAT_TYPE, NUMBER_CLASS), toFloat);
+ standardConverterMap.put(Pair.of(FLOAT_TYPE, DOUBLE_TYPE), toFloat);
+
+ /* exact types towards float */
+
+ standardConverterMap.put(Pair.of(FLOAT_CLASS, BYTE_CLASS), toFloat);
standardConverterMap.put(Pair.of(FLOAT_CLASS, SHORT_CLASS), toFloat);
standardConverterMap.put(Pair.of(FLOAT_CLASS, INTEGER_CLASS), toFloat);
standardConverterMap.put(Pair.of(FLOAT_CLASS, LONG_CLASS), toFloat);
+ standardConverterMap.put(Pair.of(FLOAT_CLASS, BYTE_TYPE), toFloat);
standardConverterMap.put(Pair.of(FLOAT_CLASS, SHORT_TYPE), toFloat);
standardConverterMap.put(Pair.of(FLOAT_CLASS, INTEGER_TYPE), toFloat);
standardConverterMap.put(Pair.of(FLOAT_CLASS, LONG_TYPE), toFloat);
/* string to float */
- Converter<Float> stringToFloat = new Converter<Float>()
- {
- @Override
- public Float convert(Object o)
- {
- return Float.valueOf(String.valueOf(o));
- }
- };
+
+ Converter<Float> stringToFloat = o -> Float.valueOf(String.valueOf(o));
+
standardConverterMap.put(Pair.of(FLOAT_CLASS, STRING_CLASS), stringToFloat);
standardConverterMap.put(Pair.of(FLOAT_TYPE, STRING_CLASS), stringToFloat);
- /* exact or widening towards Double */
- Converter<Double> toDouble = new Converter<Double>()
- {
- @Override
- public Double convert(Object o)
- {
- if (o == null) return null;
- return ((Number) o).doubleValue();
- }
- };
+ /*
+ * Conversions towards double
+ */
+
+ Converter<Double> toDouble = o -> Optional.ofNullable((Number)o)
+ .map(Number::doubleValue)
+ .orElse(null);
+
+ /* narrowing towards double */
+
+ standardConverterMap.put(Pair.of(DOUBLE_CLASS, BIG_INTEGER_CLASS), toDouble);
+ standardConverterMap.put(Pair.of(DOUBLE_CLASS, BIG_DECIMAL_CLASS), toDouble);
+ standardConverterMap.put(Pair.of(DOUBLE_TYPE, BIG_INTEGER_CLASS), toDouble);
+ standardConverterMap.put(Pair.of(DOUBLE_TYPE, BIG_DECIMAL_CLASS), toDouble);
+
+ /* exact types or widening towards double */
+
+ standardConverterMap.put(Pair.of(DOUBLE_CLASS, BYTE_CLASS), toDouble);
standardConverterMap.put(Pair.of(DOUBLE_CLASS, SHORT_CLASS), toDouble);
standardConverterMap.put(Pair.of(DOUBLE_CLASS, INTEGER_CLASS), toDouble);
standardConverterMap.put(Pair.of(DOUBLE_CLASS, LONG_CLASS), toDouble);
standardConverterMap.put(Pair.of(DOUBLE_CLASS, FLOAT_CLASS), toDouble);
standardConverterMap.put(Pair.of(DOUBLE_CLASS, NUMBER_CLASS), toDouble);
+ standardConverterMap.put(Pair.of(DOUBLE_CLASS, BYTE_TYPE), toDouble);
standardConverterMap.put(Pair.of(DOUBLE_CLASS, SHORT_TYPE), toDouble);
standardConverterMap.put(Pair.of(DOUBLE_CLASS, INTEGER_TYPE), toDouble);
standardConverterMap.put(Pair.of(DOUBLE_CLASS, LONG_TYPE), toDouble);
@@ -439,92 +493,112 @@ public class TypeConversionHandlerImpl implements TypeConversionHandler
standardConverterMap.put(Pair.of(DOUBLE_TYPE, NUMBER_CLASS), toDouble);
/* string to double */
- Converter<Double> stringToDouble = new Converter<Double>()
- {
- @Override
- public Double convert(Object o)
- {
- return Double.valueOf(String.valueOf(o));
- }
- };
+
+ Converter<Double> stringToDouble = o -> Double.valueOf(String.valueOf(o));
+
standardConverterMap.put(Pair.of(DOUBLE_CLASS, STRING_CLASS), stringToDouble);
standardConverterMap.put(Pair.of(DOUBLE_TYPE, STRING_CLASS), stringToDouble);
+ /*
+ * Conversions towards BigDecimal
+ */
+
+ /* exact types towards BigDecimal */
+
+ Converter<BigDecimal> exactToBigDecimal = o -> Optional.ofNullable((Number)o)
+ .map(n -> BigDecimal.valueOf(n.longValue()))
+ .orElse(null);
+
+ Converter<BigDecimal> bigIntegerToBigDecimal = o -> Optional.ofNullable((BigInteger)o)
+ .map(bi -> new BigDecimal(bi))
+ .orElse(null);
+
+ standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, BYTE_CLASS), exactToBigDecimal);
+ standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, SHORT_CLASS), exactToBigDecimal);
+ standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, INTEGER_CLASS), exactToBigDecimal);
+ standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, LONG_CLASS), exactToBigDecimal);
+ standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, BIG_INTEGER_CLASS), bigIntegerToBigDecimal);
+ standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, BYTE_TYPE), exactToBigDecimal);
+ standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, SHORT_TYPE), exactToBigDecimal);
+ standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, INTEGER_TYPE), exactToBigDecimal);
+ standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, LONG_TYPE), exactToBigDecimal);
+
+ /* approximate types towards BigDecimal */
+
+ Converter<BigDecimal> approxToBigDecimal = o -> Optional.ofNullable((Number)o)
+ .map(n -> BigDecimal.valueOf(n.doubleValue()))
+ .orElse(null);
+
+ standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, FLOAT_CLASS), approxToBigDecimal);
+ standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, DOUBLE_CLASS), approxToBigDecimal);
+ standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, FLOAT_TYPE), approxToBigDecimal);
+ standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, DOUBLE_TYPE), approxToBigDecimal);
+
+ /* string to BigDecimal */
+
+ Converter<BigDecimal> stringToBigDecimal = o -> Optional.ofNullable(o)
+ .map(s -> new BigDecimal(String.valueOf(s)))
+ .orElse(null);
+
+ standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, STRING_CLASS), stringToBigDecimal);
+
+ /*
+ * Conversions from boolean to numeric type
+ */
+
/* boolean to byte */
- Converter<Byte> booleanToByte = new Converter<Byte>()
- {
- @Override
- public Byte convert(Object o)
- {
- return o == null ? null : (Boolean) o ? (byte)1 : (byte)0;
- }
- };
+
+ Converter<Byte> booleanToByte = o -> Optional.ofNullable((Boolean)o)
+ .map(b -> b ? (byte)1 : (byte)0)
+ .orElse(null);
+
standardConverterMap.put(Pair.of(BYTE_CLASS, BOOLEAN_CLASS), booleanToByte);
standardConverterMap.put(Pair.of(BYTE_CLASS, BOOLEAN_TYPE), booleanToByte);
standardConverterMap.put(Pair.of(BYTE_TYPE, BOOLEAN_CLASS), booleanToByte);
standardConverterMap.put(Pair.of(BYTE_TYPE, BOOLEAN_TYPE), booleanToByte);
/* boolean to short */
- Converter<Short> booleanToShort = new Converter<Short>()
- {
- @Override
- public Short convert(Object o)
- {
- return o == null ? null : (Boolean) o ? (short)1 : (short)0;
- }
- };
+
+ Converter<Short> booleanToShort = o -> Optional.ofNullable((Boolean)o)
+ .map(b -> b ? (short)1 : (short)0)
+ .orElse(null);
+
standardConverterMap.put(Pair.of(SHORT_CLASS, BOOLEAN_CLASS), booleanToShort);
standardConverterMap.put(Pair.of(SHORT_CLASS, BOOLEAN_TYPE), booleanToShort);
standardConverterMap.put(Pair.of(SHORT_TYPE, BOOLEAN_CLASS), booleanToShort);
standardConverterMap.put(Pair.of(SHORT_TYPE, BOOLEAN_TYPE), booleanToShort);
/* boolean to integer */
- Converter<Integer> booleanToInteger = new Converter<Integer>()
- {
- @Override
- public Integer convert(Object o)
- {
- return o == null ? null : (Boolean) o ? (Integer)1 : (Integer)0;
- }
- };
+
+ Converter<Integer> booleanToInteger = o -> Optional.ofNullable((Boolean)o)
+ .map(b -> b ? (int)1 : (int)0)
+ .orElse(null);
+
standardConverterMap.put(Pair.of(INTEGER_CLASS, BOOLEAN_CLASS), booleanToInteger);
standardConverterMap.put(Pair.of(INTEGER_CLASS, BOOLEAN_TYPE), booleanToInteger);
standardConverterMap.put(Pair.of(INTEGER_TYPE, BOOLEAN_CLASS), booleanToInteger);
standardConverterMap.put(Pair.of(INTEGER_TYPE, BOOLEAN_TYPE), booleanToInteger);
- /* boolean to lonf */
- Converter<Long> booleanToLong = new Converter<Long>()
- {
- @Override
- public Long convert(Object o)
- {
- return o == null ? null : (Boolean) o ? 1L : 0L;
- }
- };
+ /* boolean to long */
+
+ Converter<Long> booleanToLong = o -> Optional.ofNullable((Boolean)o)
+ .map(b -> b ? 1l : 0l)
+ .orElse(null);
+
standardConverterMap.put(Pair.of(LONG_CLASS, BOOLEAN_CLASS), booleanToLong);
standardConverterMap.put(Pair.of(LONG_CLASS, BOOLEAN_TYPE), booleanToLong);
standardConverterMap.put(Pair.of(LONG_TYPE, BOOLEAN_CLASS), booleanToLong);
standardConverterMap.put(Pair.of(LONG_TYPE, BOOLEAN_TYPE), booleanToLong);
/* to string */
- toString = new Converter<String>()
- {
- @Override
- public String convert(Object o)
- {
- return String.valueOf(o);
- }
- };
+
+ toString = o -> String.valueOf(o);
/* string to locale */
- Converter<Locale> stringToLocale = new Converter<Locale>()
- {
- @Override
- public Locale convert(Object o)
- {
- return o == null ? null : LocaleUtils.toLocale((String)o);
- }
- };
+ Converter<Locale> stringToLocale = o -> Optional.ofNullable(o)
+ .map(l -> LocaleUtils.toLocale(String.valueOf(l)))
+ .orElse(null);
+
standardConverterMap.put(Pair.of(LOCALE_CLASS, STRING_CLASS), stringToLocale);
}
@@ -607,14 +681,7 @@ public class TypeConversionHandlerImpl implements TypeConversionHandler
else if (formalClass != null && formalClass.isEnum() && actual == String.class)
{
final Class<Enum> enumClass = (Class<Enum>)formalClass;
- converter = new Converter()
- {
- @Override
- public Object convert(Object o)
- {
- return Enum.valueOf(enumClass, (String) o);
- }
- };
+ converter = o -> Enum.valueOf(enumClass, (String)o);
}
converterCacheMap.put(key, converter == null ? cacheMiss : converter);
diff --git a/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectImpl.java b/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectImpl.java
index 96dd7956..4d5730b8 100644
--- a/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectImpl.java
+++ b/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectImpl.java
@@ -526,13 +526,22 @@ public class UberspectImpl implements Uberspect, RuntimeServicesAware
if (converters != null)
{
- for (int i = 0; i < actual.length; ++i)
+ // some converters may throw an ArithmeticException
+ // which we want to wrap into an IllegalArgumentException
+ try
{
- if (converters[i] != null)
+ for (int i = 0; i < actual.length; ++i)
{
- actual[i] = converters[i].convert(actual[i]);
+ if (converters[i] != null)
+ {
+ actual[i] = converters[i].convert(actual[i]);
+ }
}
}
+ catch (ArithmeticException ae)
+ {
+ throw new IllegalArgumentException(ae);
+ }
}
// call extension point invocation