From ca3c285b42e97b65fb02c03bf68bb55fbcebb8db Mon Sep 17 00:00:00 2001 From: Ken Partlow Date: Thu, 11 Jan 2024 22:43:13 -0500 Subject: [PATCH] Broke out more conversions and updated tests --- .../util/convert/AtomicBooleanConversion.java | 49 +++++ .../util/convert/BooleanConversion.java | 53 +++--- .../util/convert/CalendarConversion.java | 30 +++ .../util/convert/CommonValues.java | 4 + .../cedarsoftware/util/convert/Converter.java | 172 +++++++++--------- .../util/convert/ConverterOptions.java | 4 +- .../util/convert/DateConversion.java | 18 ++ .../util/convert/MapConversion.java | 90 +++++++++ .../util/convert/NumberConversion.java | 72 ++++++-- .../util/convert/VoidConversion.java | 9 + .../util/convert/ConverterTest.java | 116 +++++++----- 11 files changed, 444 insertions(+), 173 deletions(-) create mode 100644 src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversion.java create mode 100644 src/main/java/com/cedarsoftware/util/convert/CalendarConversion.java create mode 100644 src/main/java/com/cedarsoftware/util/convert/DateConversion.java create mode 100644 src/main/java/com/cedarsoftware/util/convert/MapConversion.java diff --git a/src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversion.java b/src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversion.java new file mode 100644 index 000000000..a823bab1b --- /dev/null +++ b/src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversion.java @@ -0,0 +1,49 @@ +package com.cedarsoftware.util.convert; + +import java.math.BigDecimal; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +public class AtomicBooleanConversion { + + public static Byte toByte(Object from, Converter converter, ConverterOptions options) { + AtomicBoolean b = (AtomicBoolean) from; + return b.get() ? CommonValues.BYTE_ONE : CommonValues.BYTE_ZERO; + } + + public static Short toShort(Object from, Converter converter, ConverterOptions options) { + AtomicBoolean b = (AtomicBoolean) from; + return b.get() ? CommonValues.SHORT_ONE : CommonValues.SHORT_ZERO; + } + + public static Integer toInteger(Object from, Converter converter, ConverterOptions options) { + AtomicBoolean b = (AtomicBoolean) from; + return b.get() ? CommonValues.INTEGER_ONE : CommonValues.INTEGER_ZERO; + } + + public static Long toLong(Object from, Converter converter, ConverterOptions options) { + AtomicBoolean b = (AtomicBoolean) from; + return b.get() ? CommonValues.LONG_ONE : CommonValues.LONG_ZERO; + } + + public static AtomicInteger toAtomicInteger(Object from, Converter converter, ConverterOptions options) { + AtomicBoolean b = (AtomicBoolean) from; + return b.get() ? new AtomicInteger(1) : new AtomicInteger (0); + } + + public static AtomicLong toAtomicLong(Object from, Converter converter, ConverterOptions options) { + AtomicBoolean b = (AtomicBoolean) from; + return b.get() ? new AtomicLong(1) : new AtomicLong(0); + } + + public static Character toCharacter(Object from, Converter converter, ConverterOptions options) { + AtomicBoolean b = (AtomicBoolean) from; + return b.get() ? CommonValues.CHARACTER_ONE : CommonValues.CHARACTER_ZERO; + } + + public static BigDecimal toBigDecimal(Object from, Converter converter, ConverterOptions options) { + AtomicBoolean b = (AtomicBoolean) from; + return b.get() ? BigDecimal.ONE : BigDecimal.ZERO; + } +} diff --git a/src/main/java/com/cedarsoftware/util/convert/BooleanConversion.java b/src/main/java/com/cedarsoftware/util/convert/BooleanConversion.java index 817d18abd..e119c069b 100644 --- a/src/main/java/com/cedarsoftware/util/convert/BooleanConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/BooleanConversion.java @@ -1,6 +1,8 @@ package com.cedarsoftware.util.convert; +import java.math.BigDecimal; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; /** * @author John DeRegnaucourt (jdereg@gmail.com) @@ -36,14 +38,39 @@ public static Integer toInteger(Object from, Converter converter, ConverterOptio return b.booleanValue() ? CommonValues.INTEGER_ONE : CommonValues.INTEGER_ZERO; } + public static AtomicLong toAtomicLong(Object from, Converter converter, ConverterOptions options) { + Boolean b = (Boolean) from; + return new AtomicLong(b.booleanValue() ? 1 : 0); + } + public static Long toLong(Object from, Converter converter, ConverterOptions options) { Boolean b = (Boolean) from; return b.booleanValue() ? CommonValues.LONG_ONE : CommonValues.LONG_ZERO; } - public static AtomicBoolean numberToAtomicBoolean(Object from, Converter converter, ConverterOptions options) { - Number number = (Number) from; - return new AtomicBoolean(number.longValue() != 0); + public static BigDecimal toBigDecimal(Object from, Converter converter, ConverterOptions options) { + Boolean b = (Boolean)from; + return b ? BigDecimal.ONE : BigDecimal.ZERO; + } + + public static Float toFloat(Object from, Converter converter, ConverterOptions options) { + Boolean b = (Boolean) from; + return b.booleanValue() ? CommonValues.FLOAT_ONE : CommonValues.FLOAT_ZERO; + } + + public static Double toDouble(Object from, Converter converter, ConverterOptions options) { + Boolean b = (Boolean) from; + return b.booleanValue() ? CommonValues.DOUBLE_ONE : CommonValues.DOUBLE_ZERO; + } + + public static Float atomicToFloat(Object from, Converter converter, ConverterOptions options) { + AtomicBoolean b = (AtomicBoolean) from; + return b.get() ? CommonValues.FLOAT_ONE : CommonValues.FLOAT_ZERO; + } + + public static Double atomicToDouble(Object from, Converter converter, ConverterOptions options) { + AtomicBoolean b = (AtomicBoolean) from; + return b.get() ? CommonValues.DOUBLE_ONE : CommonValues.DOUBLE_ZERO; } public static Byte atomicToByte(Object from, Converter converter, ConverterOptions options) { @@ -70,24 +97,4 @@ public static Long atomicToCharacter(Object from, Converter converter, Converter AtomicBoolean b = (AtomicBoolean) from; return b.get() ? CommonValues.LONG_ONE : CommonValues.LONG_ZERO; } - - public static Float toFloat(Object from, Converter converter, ConverterOptions options) { - Boolean b = (Boolean) from; - return b.booleanValue() ? CommonValues.FLOAT_ONE : CommonValues.FLOAT_ZERO; - } - - public static Double toDouble(Object from, Converter converter, ConverterOptions options) { - Boolean b = (Boolean) from; - return b.booleanValue() ? CommonValues.DOUBLE_ONE : CommonValues.DOUBLE_ZERO; - } - - public static Float atomicToFloat(Object from, Converter converter, ConverterOptions options) { - AtomicBoolean b = (AtomicBoolean) from; - return b.get() ? CommonValues.FLOAT_ONE : CommonValues.FLOAT_ZERO; - } - - public static Double atomicToDouble(Object from, Converter converter, ConverterOptions options) { - AtomicBoolean b = (AtomicBoolean) from; - return b.get() ? CommonValues.DOUBLE_ONE : CommonValues.DOUBLE_ZERO; - } } diff --git a/src/main/java/com/cedarsoftware/util/convert/CalendarConversion.java b/src/main/java/com/cedarsoftware/util/convert/CalendarConversion.java new file mode 100644 index 000000000..012922c47 --- /dev/null +++ b/src/main/java/com/cedarsoftware/util/convert/CalendarConversion.java @@ -0,0 +1,30 @@ +package com.cedarsoftware.util.convert; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Calendar; +import java.util.Date; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +public class CalendarConversion { + public static Date toDate(Object fromInstance, Converter converter, ConverterOptions options) { + Calendar from = (Calendar)fromInstance; + return from.getTime(); + } + + public static AtomicLong toAtomicLong(Object fromInstance, Converter converter, ConverterOptions options) { + Calendar from = (Calendar)fromInstance; + return new AtomicLong(from.getTime().getTime()); + } + + public static BigDecimal toBigDecimal(Object fromInstance, Converter converter, ConverterOptions options) { + Calendar from = (Calendar)fromInstance; + return BigDecimal.valueOf(from.getTime().getTime()); + } + + public static BigInteger toBigInteger(Object fromInstance, Converter converter, ConverterOptions options) { + Calendar from = (Calendar)fromInstance; + return BigInteger.valueOf(from.getTime().getTime()); + } +} diff --git a/src/main/java/com/cedarsoftware/util/convert/CommonValues.java b/src/main/java/com/cedarsoftware/util/convert/CommonValues.java index c3352cd97..398647c83 100644 --- a/src/main/java/com/cedarsoftware/util/convert/CommonValues.java +++ b/src/main/java/com/cedarsoftware/util/convert/CommonValues.java @@ -30,4 +30,8 @@ public class CommonValues { public static final Float FLOAT_ONE = 1.0f; public static final Double DOUBLE_ZERO = 0.0d; public static final Double DOUBLE_ONE = 1.0d; + + public static final Character CHARACTER_ZERO = '0'; + + public static final Character CHARACTER_ONE = '1'; } diff --git a/src/main/java/com/cedarsoftware/util/convert/Converter.java b/src/main/java/com/cedarsoftware/util/convert/Converter.java index 6eb90fec1..5465b257c 100644 --- a/src/main/java/com/cedarsoftware/util/convert/Converter.java +++ b/src/main/java/com/cedarsoftware/util/convert/Converter.java @@ -83,7 +83,7 @@ public final class Converter { private static final Map, Set> cacheParentTypes = new ConcurrentHashMap<>(); private static final Map, Class> primitiveToWrapper = new HashMap<>(20, .8f); private static final Map, Class>, Convert> DEFAULT_FACTORY = new ConcurrentHashMap<>(500, .8f); - + // Create a Map.Entry (pair) of source class to target class. private static Map.Entry, Class> pair(Class source, Class target) { return new AbstractMap.SimpleImmutableEntry<>(source, target); @@ -108,7 +108,7 @@ private static void buildPrimitiveWrappers() { private static void buildFactoryConversions() { // Byte/byte Conversions supported - DEFAULT_FACTORY.put(pair(Void.class, byte.class), (fromInstance, converter, options) -> (byte) 0); + DEFAULT_FACTORY.put(pair(Void.class, byte.class), NumberConversion::toByteZero); DEFAULT_FACTORY.put(pair(Void.class, Byte.class), VoidConversion::toNull); DEFAULT_FACTORY.put(pair(Byte.class, Byte.class), Converter::identity); DEFAULT_FACTORY.put(pair(Short.class, Byte.class), NumberConversion::toByte); @@ -119,17 +119,17 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(Boolean.class, Byte.class), BooleanConversion::toByte); DEFAULT_FACTORY.put(pair(Character.class, Byte.class), (fromInstance, converter, options) -> (byte) ((Character) fromInstance).charValue()); DEFAULT_FACTORY.put(pair(Calendar.class, Byte.class), NumberConversion::toByte); - DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Byte.class), BooleanConversion::atomicToByte); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Byte.class), AtomicBooleanConversion::toByte); DEFAULT_FACTORY.put(pair(AtomicInteger.class, Byte.class), NumberConversion::toByte); DEFAULT_FACTORY.put(pair(AtomicLong.class, Byte.class), NumberConversion::toByte); DEFAULT_FACTORY.put(pair(BigInteger.class, Byte.class), NumberConversion::toByte); DEFAULT_FACTORY.put(pair(BigDecimal.class, Byte.class), NumberConversion::toByte); DEFAULT_FACTORY.put(pair(Number.class, Byte.class), NumberConversion::toByte); - DEFAULT_FACTORY.put(pair(Map.class, Byte.class), (fromInstance, converter, options) -> converter.fromValueMap((Map) fromInstance, byte.class, null, options)); + DEFAULT_FACTORY.put(pair(Map.class, Byte.class), MapConversion::toByte); DEFAULT_FACTORY.put(pair(String.class, Byte.class), StringConversion::stringToByte); // Short/short conversions supported - DEFAULT_FACTORY.put(pair(Void.class, short.class), (fromInstance, converter, options) -> (short) 0); + DEFAULT_FACTORY.put(pair(Void.class, short.class), NumberConversion::toShortZero); DEFAULT_FACTORY.put(pair(Void.class, Short.class), VoidConversion::toNull); DEFAULT_FACTORY.put(pair(Byte.class, Short.class), NumberConversion::toShort); DEFAULT_FACTORY.put(pair(Short.class, Short.class), Converter::identity); @@ -139,7 +139,7 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(Double.class, Short.class), NumberConversion::toShort); DEFAULT_FACTORY.put(pair(Boolean.class, Short.class), BooleanConversion::toShort); DEFAULT_FACTORY.put(pair(Character.class, Short.class), (fromInstance, converter, options) -> (short) ((Character) fromInstance).charValue()); - DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Short.class), BooleanConversion::atomicToShort); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Short.class), AtomicBooleanConversion::toShort); DEFAULT_FACTORY.put(pair(AtomicInteger.class, Short.class), NumberConversion::toShort); DEFAULT_FACTORY.put(pair(AtomicLong.class, Short.class), NumberConversion::toShort); DEFAULT_FACTORY.put(pair(BigInteger.class, Short.class), NumberConversion::toShort); @@ -150,7 +150,7 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(String.class, Short.class), StringConversion::stringToShort); // Integer/int conversions supported - DEFAULT_FACTORY.put(pair(Void.class, int.class), (fromInstance, converter, options) -> 0); + DEFAULT_FACTORY.put(pair(Void.class, int.class), NumberConversion::toIntZero); DEFAULT_FACTORY.put(pair(Void.class, Integer.class), VoidConversion::toNull); DEFAULT_FACTORY.put(pair(Byte.class, Integer.class), NumberConversion::toInt); DEFAULT_FACTORY.put(pair(Short.class, Integer.class), NumberConversion::toInt); @@ -160,18 +160,18 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(Double.class, Integer.class), NumberConversion::toInt); DEFAULT_FACTORY.put(pair(Boolean.class, Integer.class), BooleanConversion::toInteger); DEFAULT_FACTORY.put(pair(Character.class, Integer.class), (fromInstance, converter, options) -> (int) (Character) fromInstance); - DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Integer.class), BooleanConversion::atomicToInteger); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Integer.class), AtomicBooleanConversion::toInteger); DEFAULT_FACTORY.put(pair(AtomicInteger.class, Integer.class), NumberConversion::toInt); DEFAULT_FACTORY.put(pair(AtomicLong.class, Integer.class), NumberConversion::toInt); DEFAULT_FACTORY.put(pair(BigInteger.class, Integer.class), NumberConversion::toInt); DEFAULT_FACTORY.put(pair(BigDecimal.class, Integer.class), NumberConversion::toInt); DEFAULT_FACTORY.put(pair(LocalDate.class, Integer.class), (fromInstance, converter, options) -> (int) ((LocalDate) fromInstance).toEpochDay()); DEFAULT_FACTORY.put(pair(Number.class, Integer.class), NumberConversion::toInt); - DEFAULT_FACTORY.put(pair(Map.class, Integer.class), (fromInstance, converter, options) -> converter.fromValueMap((Map) fromInstance, int.class, null, options)); + DEFAULT_FACTORY.put(pair(Map.class, Integer.class), MapConversion::toInt); DEFAULT_FACTORY.put(pair(String.class, Integer.class), StringConversion::stringToInteger); // Long/long conversions supported - DEFAULT_FACTORY.put(pair(Void.class, long.class), (fromInstance, converter, options) -> 0L); + DEFAULT_FACTORY.put(pair(Void.class, long.class), NumberConversion::toLongZero); DEFAULT_FACTORY.put(pair(Void.class, Long.class), VoidConversion::toNull); DEFAULT_FACTORY.put(pair(Byte.class, Long.class), NumberConversion::toLong); DEFAULT_FACTORY.put(pair(Short.class, Long.class), NumberConversion::toLong); @@ -181,7 +181,7 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(Double.class, Long.class), NumberConversion::toLong); DEFAULT_FACTORY.put(pair(Boolean.class, Long.class), BooleanConversion::toLong); DEFAULT_FACTORY.put(pair(Character.class, Long.class), (fromInstance, converter, options) -> (long) ((char) fromInstance)); - DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Long.class), BooleanConversion::atomicToLong); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Long.class), AtomicBooleanConversion::toLong); DEFAULT_FACTORY.put(pair(AtomicInteger.class, Long.class), NumberConversion::toLong); DEFAULT_FACTORY.put(pair(AtomicLong.class, Long.class), NumberConversion::toLong); DEFAULT_FACTORY.put(pair(BigInteger.class, Long.class), NumberConversion::toLong); @@ -194,11 +194,11 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(ZonedDateTime.class, Long.class), (fromInstance, converter, options) -> zonedDateTimeToMillis((ZonedDateTime) fromInstance)); DEFAULT_FACTORY.put(pair(Calendar.class, Long.class), (fromInstance, converter, options) -> ((Calendar) fromInstance).getTime().getTime()); DEFAULT_FACTORY.put(pair(Number.class, Long.class), NumberConversion::toLong); - DEFAULT_FACTORY.put(pair(Map.class, Long.class), (fromInstance, converter, options) -> converter.fromValueMap((Map) fromInstance, long.class, null, options)); + DEFAULT_FACTORY.put(pair(Map.class, Long.class), MapConversion::toLong); DEFAULT_FACTORY.put(pair(String.class, Long.class), StringConversion::stringToLong); // Float/float conversions supported - DEFAULT_FACTORY.put(pair(Void.class, float.class), (fromInstance, converter, options) -> 0.0f); + DEFAULT_FACTORY.put(pair(Void.class, float.class), NumberConversion::toFloatZero); DEFAULT_FACTORY.put(pair(Void.class, Float.class), VoidConversion::toNull); DEFAULT_FACTORY.put(pair(Byte.class, Float.class), NumberConversion::toFloat); DEFAULT_FACTORY.put(pair(Short.class, Float.class), NumberConversion::toFloat); @@ -215,7 +215,7 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(BigInteger.class, Float.class), NumberConversion::toFloat); DEFAULT_FACTORY.put(pair(BigDecimal.class, Float.class), NumberConversion::toFloat); DEFAULT_FACTORY.put(pair(Number.class, Float.class), NumberConversion::toFloat); - DEFAULT_FACTORY.put(pair(Map.class, Float.class), (fromInstance, converter, options) -> converter.fromValueMap((Map) fromInstance, float.class, null, options)); + DEFAULT_FACTORY.put(pair(Map.class, Float.class), MapConversion::toFloat); DEFAULT_FACTORY.put(pair(String.class, Float.class), StringConversion::stringToFloat); // Double/double conversions supported @@ -242,11 +242,11 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(BigDecimal.class, Double.class), NumberConversion::toDouble); DEFAULT_FACTORY.put(pair(Calendar.class, Double.class), (fromInstance, converter, options) -> (double) ((Calendar) fromInstance).getTime().getTime()); DEFAULT_FACTORY.put(pair(Number.class, Double.class), NumberConversion::toDouble); - DEFAULT_FACTORY.put(pair(Map.class, Double.class), (fromInstance, converter, options) -> converter.fromValueMap((Map) fromInstance, double.class, null, options)); + DEFAULT_FACTORY.put(pair(Map.class, Double.class), MapConversion::toDouble); DEFAULT_FACTORY.put(pair(String.class, Double.class), StringConversion::stringToDouble); // Boolean/boolean conversions supported - DEFAULT_FACTORY.put(pair(Void.class, boolean.class), (fromInstance, converter, options) -> false); + DEFAULT_FACTORY.put(pair(Void.class, boolean.class), VoidConversion::toBoolean); DEFAULT_FACTORY.put(pair(Void.class, Boolean.class), VoidConversion::toNull); DEFAULT_FACTORY.put(pair(Byte.class, Boolean.class), NumberConversion::isIntTypeNotZero); DEFAULT_FACTORY.put(pair(Short.class, Boolean.class), NumberConversion::isIntTypeNotZero); @@ -262,7 +262,7 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(BigInteger.class, Boolean.class), (fromInstance, converter, options) -> ((BigInteger)fromInstance).compareTo(BigInteger.ZERO) != 0); DEFAULT_FACTORY.put(pair(BigDecimal.class, Boolean.class), (fromInstance, converter, options) -> ((BigDecimal)fromInstance).compareTo(BigDecimal.ZERO) != 0); DEFAULT_FACTORY.put(pair(Number.class, Boolean.class), NumberConversion::isIntTypeNotZero); - DEFAULT_FACTORY.put(pair(Map.class, Boolean.class), (fromInstance, converter, options) -> converter.fromValueMap((Map) fromInstance, boolean.class, null, options)); + DEFAULT_FACTORY.put(pair(Map.class, Boolean.class), MapConversion::toBoolean); DEFAULT_FACTORY.put(pair(String.class, Boolean.class), (fromInstance, converter, options) -> { String str = ((String) fromInstance).trim(); if (str.isEmpty()) { @@ -278,7 +278,7 @@ private static void buildFactoryConversions() { }); // Character/chat conversions supported - DEFAULT_FACTORY.put(pair(Void.class, char.class), (fromInstance, converter, options) -> (char) 0); + DEFAULT_FACTORY.put(pair(Void.class, char.class), VoidConversion::toChar); DEFAULT_FACTORY.put(pair(Void.class, Character.class), VoidConversion::toNull); DEFAULT_FACTORY.put(pair(Byte.class, Character.class), NumberConversion::numberToCharacter); DEFAULT_FACTORY.put(pair(Short.class, Character.class), NumberConversion::numberToCharacter); @@ -288,7 +288,7 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(Double.class, Character.class), NumberConversion::numberToCharacter); DEFAULT_FACTORY.put(pair(Boolean.class, Character.class), (fromInstance, converter, options) -> ((Boolean) fromInstance) ? '1' : '0'); DEFAULT_FACTORY.put(pair(Character.class, Character.class), Converter::identity); - DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Character.class), (fromInstance, converter, options) -> ((AtomicBoolean) fromInstance).get() ? '1' : '0'); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Character.class), AtomicBooleanConversion::toCharacter); DEFAULT_FACTORY.put(pair(AtomicInteger.class, Character.class), NumberConversion::numberToCharacter); DEFAULT_FACTORY.put(pair(AtomicLong.class, Character.class), NumberConversion::numberToCharacter); DEFAULT_FACTORY.put(pair(BigInteger.class, Character.class), NumberConversion::numberToCharacter); @@ -335,9 +335,9 @@ private static void buildFactoryConversions() { // Shift the most significant bits to the left and add the least significant bits return mostSignificant.shiftLeft(64).add(leastSignificant); }); - DEFAULT_FACTORY.put(pair(Calendar.class, BigInteger.class), (fromInstance, converter, options) -> BigInteger.valueOf(((Calendar) fromInstance).getTime().getTime())); + DEFAULT_FACTORY.put(pair(Calendar.class, BigInteger.class), CalendarConversion::toBigInteger); DEFAULT_FACTORY.put(pair(Number.class, BigInteger.class), (fromInstance, converter, options) -> new BigInteger(fromInstance.toString())); - DEFAULT_FACTORY.put(pair(Map.class, BigInteger.class), (fromInstance, converter, options) -> converter.fromValueMap((Map) fromInstance, BigInteger.class, null, options)); + DEFAULT_FACTORY.put(pair(Map.class, BigInteger.class), MapConversion::toBigInteger); DEFAULT_FACTORY.put(pair(String.class, BigInteger.class), (fromInstance, converter, options) -> { String str = ((String) fromInstance).trim(); if (str.isEmpty()) { @@ -351,24 +351,26 @@ private static void buildFactoryConversions() { } }); + + // BigDecimal conversions supported DEFAULT_FACTORY.put(pair(Void.class, BigDecimal.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Byte.class, BigDecimal.class), NumberConversion::longToBigDecimal); - DEFAULT_FACTORY.put(pair(Short.class, BigDecimal.class), NumberConversion::longToBigDecimal); - DEFAULT_FACTORY.put(pair(Integer.class, BigDecimal.class), NumberConversion::longToBigDecimal); - DEFAULT_FACTORY.put(pair(Long.class, BigDecimal.class), NumberConversion::longToBigDecimal); - DEFAULT_FACTORY.put(pair(Float.class, BigDecimal.class), (fromInstance, converter, options) -> BigDecimal.valueOf((Float) fromInstance)); - DEFAULT_FACTORY.put(pair(Double.class, BigDecimal.class), (fromInstance, converter, options) -> BigDecimal.valueOf((Double) fromInstance)); - DEFAULT_FACTORY.put(pair(Boolean.class, BigDecimal.class), (fromInstance, converter, options) -> (Boolean) fromInstance ? BigDecimal.ONE : BigDecimal.ZERO); + DEFAULT_FACTORY.put(pair(Byte.class, BigDecimal.class), NumberConversion::integerTypeToBigDecimal); + DEFAULT_FACTORY.put(pair(Short.class, BigDecimal.class), NumberConversion::integerTypeToBigDecimal); + DEFAULT_FACTORY.put(pair(Integer.class, BigDecimal.class), NumberConversion::integerTypeToBigDecimal); + DEFAULT_FACTORY.put(pair(Long.class, BigDecimal.class), NumberConversion::integerTypeToBigDecimal); + DEFAULT_FACTORY.put(pair(Float.class, BigDecimal.class), NumberConversion::floatingPointToBigDecimal); + DEFAULT_FACTORY.put(pair(Double.class, BigDecimal.class), NumberConversion::floatingPointToBigDecimal); + DEFAULT_FACTORY.put(pair(Boolean.class, BigDecimal.class), BooleanConversion::toBigDecimal); DEFAULT_FACTORY.put(pair(Character.class, BigDecimal.class), (fromInstance, converter, options) -> BigDecimal.valueOf(((char) fromInstance))); DEFAULT_FACTORY.put(pair(BigDecimal.class, BigDecimal.class), Converter::identity); - DEFAULT_FACTORY.put(pair(BigInteger.class, BigDecimal.class), (fromInstance, converter, options) -> new BigDecimal((BigInteger) fromInstance)); - DEFAULT_FACTORY.put(pair(AtomicBoolean.class, BigDecimal.class), (fromInstance, converter, options) -> ((AtomicBoolean) fromInstance).get() ? BigDecimal.ONE : BigDecimal.ZERO); - DEFAULT_FACTORY.put(pair(AtomicInteger.class, BigDecimal.class), NumberConversion::longToBigDecimal); - DEFAULT_FACTORY.put(pair(AtomicLong.class, BigDecimal.class), NumberConversion::longToBigDecimal); - DEFAULT_FACTORY.put(pair(Date.class, BigDecimal.class), (fromInstance, converter, options) -> BigDecimal.valueOf(((Date) fromInstance).getTime())); - DEFAULT_FACTORY.put(pair(java.sql.Date.class, BigDecimal.class), (fromInstance, converter, options) -> BigDecimal.valueOf(((Date) fromInstance).getTime())); - DEFAULT_FACTORY.put(pair(Timestamp.class, BigDecimal.class), (fromInstance, converter, options) -> BigDecimal.valueOf(((Date) fromInstance).getTime())); + DEFAULT_FACTORY.put(pair(BigInteger.class, BigDecimal.class), NumberConversion::bigIntegerToBigDecimal); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, BigDecimal.class), AtomicBooleanConversion::toBigDecimal); + DEFAULT_FACTORY.put(pair(AtomicInteger.class, BigDecimal.class), NumberConversion::integerTypeToBigDecimal); + DEFAULT_FACTORY.put(pair(AtomicLong.class, BigDecimal.class), NumberConversion::integerTypeToBigDecimal); + DEFAULT_FACTORY.put(pair(Date.class, BigDecimal.class), DateConversion::toBigDecimal); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, BigDecimal.class), DateConversion::toBigDecimal); + DEFAULT_FACTORY.put(pair(Timestamp.class, BigDecimal.class), DateConversion::toBigDecimal); DEFAULT_FACTORY.put(pair(LocalDate.class, BigDecimal.class), (fromInstance, converter, options) -> BigDecimal.valueOf(((LocalDate) fromInstance).toEpochDay())); DEFAULT_FACTORY.put(pair(LocalDateTime.class, BigDecimal.class), (fromInstance, converter, options) -> BigDecimal.valueOf(localDateTimeToMillis((LocalDateTime) fromInstance, options.getSourceZoneId()))); DEFAULT_FACTORY.put(pair(ZonedDateTime.class, BigDecimal.class), (fromInstance, converter, options) -> BigDecimal.valueOf(zonedDateTimeToMillis((ZonedDateTime) fromInstance))); @@ -379,9 +381,9 @@ private static void buildFactoryConversions() { // Shift the most significant bits to the left and add the least significant bits return new BigDecimal(mostSignificant.shiftLeft(64).add(leastSignificant)); }); - DEFAULT_FACTORY.put(pair(Calendar.class, BigDecimal.class), (fromInstance, converter, options) -> BigDecimal.valueOf(((Calendar) fromInstance).getTime().getTime())); + DEFAULT_FACTORY.put(pair(Calendar.class, BigDecimal.class), CalendarConversion::toBigDecimal); DEFAULT_FACTORY.put(pair(Number.class, BigDecimal.class), (fromInstance, converter, options) -> new BigDecimal(fromInstance.toString())); - DEFAULT_FACTORY.put(pair(Map.class, BigDecimal.class), (fromInstance, converter, options) -> converter.fromValueMap((Map) fromInstance, BigDecimal.class, null, options)); + DEFAULT_FACTORY.put(pair(Map.class, BigDecimal.class), MapConversion::toBigDecimal); DEFAULT_FACTORY.put(pair(String.class, BigDecimal.class), (fromInstance, converter, options) -> { String str = ((String) fromInstance).trim(); if (str.isEmpty()) { @@ -396,20 +398,20 @@ private static void buildFactoryConversions() { // AtomicBoolean conversions supported DEFAULT_FACTORY.put(pair(Void.class, AtomicBoolean.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Byte.class, AtomicBoolean.class), BooleanConversion::numberToAtomicBoolean); - DEFAULT_FACTORY.put(pair(Short.class, AtomicBoolean.class), BooleanConversion::numberToAtomicBoolean); - DEFAULT_FACTORY.put(pair(Integer.class, AtomicBoolean.class), BooleanConversion::numberToAtomicBoolean); - DEFAULT_FACTORY.put(pair(Long.class, AtomicBoolean.class), BooleanConversion::numberToAtomicBoolean); - DEFAULT_FACTORY.put(pair(Float.class, AtomicBoolean.class), BooleanConversion::numberToAtomicBoolean); - DEFAULT_FACTORY.put(pair(Double.class, AtomicBoolean.class), BooleanConversion::numberToAtomicBoolean); + DEFAULT_FACTORY.put(pair(Byte.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(Short.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(Integer.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(Long.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(Float.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(Double.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); DEFAULT_FACTORY.put(pair(Boolean.class, AtomicBoolean.class), (fromInstance, converter, options) -> new AtomicBoolean((Boolean) fromInstance)); DEFAULT_FACTORY.put(pair(Character.class, AtomicBoolean.class), (fromInstance, converter, options) -> new AtomicBoolean((char) fromInstance > 0)); - DEFAULT_FACTORY.put(pair(BigInteger.class, AtomicBoolean.class), BooleanConversion::numberToAtomicBoolean); - DEFAULT_FACTORY.put(pair(BigDecimal.class, AtomicBoolean.class), BooleanConversion::numberToAtomicBoolean); + DEFAULT_FACTORY.put(pair(BigInteger.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(BigDecimal.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); DEFAULT_FACTORY.put(pair(AtomicBoolean.class, AtomicBoolean.class), (fromInstance, converter, options) -> new AtomicBoolean(((AtomicBoolean) fromInstance).get())); // mutable, so dupe - DEFAULT_FACTORY.put(pair(AtomicInteger.class, AtomicBoolean.class), BooleanConversion::numberToAtomicBoolean); - DEFAULT_FACTORY.put(pair(AtomicLong.class, AtomicBoolean.class), BooleanConversion::numberToAtomicBoolean); - DEFAULT_FACTORY.put(pair(Number.class, AtomicBoolean.class), BooleanConversion::numberToAtomicBoolean); + DEFAULT_FACTORY.put(pair(AtomicInteger.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(AtomicLong.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(Number.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); DEFAULT_FACTORY.put(pair(Map.class, AtomicBoolean.class), (fromInstance, converter, options) -> converter.fromValueMap((Map) fromInstance, AtomicBoolean.class, null, options)); DEFAULT_FACTORY.put(pair(String.class, AtomicBoolean.class), (fromInstance, converter, options) -> { String str = ((String) fromInstance).trim(); @@ -421,47 +423,47 @@ private static void buildFactoryConversions() { // AtomicInteger conversions supported DEFAULT_FACTORY.put(pair(Void.class, AtomicInteger.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Byte.class, AtomicInteger.class), NumberConversion::numberToAtomicInteger); - DEFAULT_FACTORY.put(pair(Short.class, AtomicInteger.class), NumberConversion::numberToAtomicInteger); - DEFAULT_FACTORY.put(pair(Integer.class, AtomicInteger.class), NumberConversion::numberToAtomicInteger); - DEFAULT_FACTORY.put(pair(Long.class, AtomicInteger.class), NumberConversion::numberToAtomicInteger); - DEFAULT_FACTORY.put(pair(Float.class, AtomicInteger.class), NumberConversion::numberToAtomicInteger); - DEFAULT_FACTORY.put(pair(Double.class, AtomicInteger.class), NumberConversion::numberToAtomicInteger); + DEFAULT_FACTORY.put(pair(Byte.class, AtomicInteger.class), NumberConversion::toAtomicInteger); + DEFAULT_FACTORY.put(pair(Short.class, AtomicInteger.class), NumberConversion::toAtomicInteger); + DEFAULT_FACTORY.put(pair(Integer.class, AtomicInteger.class), NumberConversion::toAtomicInteger); + DEFAULT_FACTORY.put(pair(Long.class, AtomicInteger.class), NumberConversion::toAtomicInteger); + DEFAULT_FACTORY.put(pair(Float.class, AtomicInteger.class), NumberConversion::toAtomicInteger); + DEFAULT_FACTORY.put(pair(Double.class, AtomicInteger.class), NumberConversion::toAtomicInteger); DEFAULT_FACTORY.put(pair(Boolean.class, AtomicInteger.class), (fromInstance, converter, options) -> ((Boolean) fromInstance) ? new AtomicInteger(1) : new AtomicInteger(0)); DEFAULT_FACTORY.put(pair(Character.class, AtomicInteger.class), (fromInstance, converter, options) -> new AtomicInteger(((char) fromInstance))); - DEFAULT_FACTORY.put(pair(BigInteger.class, AtomicInteger.class), NumberConversion::numberToAtomicInteger); - DEFAULT_FACTORY.put(pair(BigDecimal.class, AtomicInteger.class), NumberConversion::numberToAtomicInteger); - DEFAULT_FACTORY.put(pair(AtomicInteger.class, AtomicInteger.class), NumberConversion::numberToAtomicInteger); // mutable, so dupe + DEFAULT_FACTORY.put(pair(BigInteger.class, AtomicInteger.class), NumberConversion::toAtomicInteger); + DEFAULT_FACTORY.put(pair(BigDecimal.class, AtomicInteger.class), NumberConversion::toAtomicInteger); + DEFAULT_FACTORY.put(pair(AtomicInteger.class, AtomicInteger.class), NumberConversion::toAtomicInteger); // mutable, so dupe DEFAULT_FACTORY.put(pair(AtomicBoolean.class, AtomicInteger.class), (fromInstance, converter, options) -> ((AtomicBoolean) fromInstance).get() ? new AtomicInteger(1) : new AtomicInteger(0)); - DEFAULT_FACTORY.put(pair(AtomicLong.class, AtomicInteger.class), NumberConversion::numberToAtomicInteger); + DEFAULT_FACTORY.put(pair(AtomicLong.class, AtomicInteger.class), NumberConversion::toAtomicInteger); DEFAULT_FACTORY.put(pair(LocalDate.class, AtomicInteger.class), (fromInstance, converter, options) -> new AtomicInteger((int) ((LocalDate) fromInstance).toEpochDay())); - DEFAULT_FACTORY.put(pair(Number.class, AtomicBoolean.class), NumberConversion::numberToAtomicInteger); + DEFAULT_FACTORY.put(pair(Number.class, AtomicBoolean.class), NumberConversion::toAtomicInteger); DEFAULT_FACTORY.put(pair(Map.class, AtomicInteger.class), (fromInstance, converter, options) -> converter.fromValueMap((Map) fromInstance, AtomicInteger.class, null, options)); DEFAULT_FACTORY.put(pair(String.class, AtomicInteger.class), StringConversion::stringToAtomicInteger); // AtomicLong conversions supported DEFAULT_FACTORY.put(pair(Void.class, AtomicLong.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Byte.class, AtomicLong.class), NumberConversion::numberToAtomicLong); - DEFAULT_FACTORY.put(pair(Short.class, AtomicLong.class), NumberConversion::numberToAtomicLong); - DEFAULT_FACTORY.put(pair(Integer.class, AtomicLong.class), NumberConversion::numberToAtomicLong); - DEFAULT_FACTORY.put(pair(Long.class, AtomicLong.class), NumberConversion::numberToAtomicLong); - DEFAULT_FACTORY.put(pair(Float.class, AtomicLong.class), NumberConversion::numberToAtomicLong); - DEFAULT_FACTORY.put(pair(Double.class, AtomicLong.class), NumberConversion::numberToAtomicLong); - DEFAULT_FACTORY.put(pair(Boolean.class, AtomicLong.class), (fromInstance, converter, options) -> ((Boolean) fromInstance) ? new AtomicLong(1) : new AtomicLong(0)); + DEFAULT_FACTORY.put(pair(Byte.class, AtomicLong.class), NumberConversion::toAtomicLong); + DEFAULT_FACTORY.put(pair(Short.class, AtomicLong.class), NumberConversion::toAtomicLong); + DEFAULT_FACTORY.put(pair(Integer.class, AtomicLong.class), NumberConversion::toAtomicLong); + DEFAULT_FACTORY.put(pair(Long.class, AtomicLong.class), NumberConversion::toAtomicLong); + DEFAULT_FACTORY.put(pair(Float.class, AtomicLong.class), NumberConversion::toAtomicLong); + DEFAULT_FACTORY.put(pair(Double.class, AtomicLong.class), NumberConversion::toAtomicLong); + DEFAULT_FACTORY.put(pair(Boolean.class, AtomicLong.class), BooleanConversion::toAtomicLong); DEFAULT_FACTORY.put(pair(Character.class, AtomicLong.class), (fromInstance, converter, options) -> new AtomicLong(((char) fromInstance))); - DEFAULT_FACTORY.put(pair(BigInteger.class, AtomicLong.class), NumberConversion::numberToAtomicLong); - DEFAULT_FACTORY.put(pair(BigDecimal.class, AtomicLong.class), NumberConversion::numberToAtomicLong); - DEFAULT_FACTORY.put(pair(AtomicBoolean.class, AtomicLong.class), (fromInstance, converter, options) -> ((AtomicBoolean) fromInstance).get() ? new AtomicLong(1) : new AtomicLong(0)); - DEFAULT_FACTORY.put(pair(AtomicInteger.class, AtomicLong.class), NumberConversion::numberToAtomicLong); - DEFAULT_FACTORY.put(pair(AtomicLong.class, AtomicLong.class), NumberConversion::numberToAtomicLong); // mutable, so dupe - DEFAULT_FACTORY.put(pair(Date.class, AtomicLong.class), (fromInstance, converter, options) -> new AtomicLong(((Date) fromInstance).getTime())); - DEFAULT_FACTORY.put(pair(java.sql.Date.class, AtomicLong.class), (fromInstance, converter, options) -> new AtomicLong(((Date) fromInstance).getTime())); - DEFAULT_FACTORY.put(pair(Timestamp.class, AtomicLong.class), (fromInstance, converter, options) -> new AtomicLong(((Date) fromInstance).getTime())); + DEFAULT_FACTORY.put(pair(BigInteger.class, AtomicLong.class), NumberConversion::toAtomicLong); + DEFAULT_FACTORY.put(pair(BigDecimal.class, AtomicLong.class), NumberConversion::toAtomicLong); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, AtomicLong.class), AtomicBooleanConversion::toAtomicLong); + DEFAULT_FACTORY.put(pair(AtomicLong.class, AtomicLong.class), Converter::identity); // mutable, so dupe + DEFAULT_FACTORY.put(pair(AtomicInteger.class, AtomicLong.class), NumberConversion::toAtomicLong); + DEFAULT_FACTORY.put(pair(Date.class, AtomicLong.class), DateConversion::toAtomicLong); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, AtomicLong.class), DateConversion::toAtomicLong); + DEFAULT_FACTORY.put(pair(Timestamp.class, AtomicLong.class), DateConversion::toAtomicLong); DEFAULT_FACTORY.put(pair(LocalDate.class, AtomicLong.class), (fromInstance, converter, options) -> new AtomicLong(((LocalDate) fromInstance).toEpochDay())); DEFAULT_FACTORY.put(pair(LocalDateTime.class, AtomicLong.class), (fromInstance, converter, options) -> new AtomicLong(localDateTimeToMillis((LocalDateTime) fromInstance, options.getSourceZoneId()))); DEFAULT_FACTORY.put(pair(ZonedDateTime.class, AtomicLong.class), (fromInstance, converter, options) -> new AtomicLong(zonedDateTimeToMillis((ZonedDateTime) fromInstance))); - DEFAULT_FACTORY.put(pair(Calendar.class, AtomicLong.class), (fromInstance, converter, options) -> new AtomicLong(((Calendar) fromInstance).getTime().getTime())); - DEFAULT_FACTORY.put(pair(Number.class, AtomicLong.class), NumberConversion::numberToAtomicLong); + DEFAULT_FACTORY.put(pair(Calendar.class, AtomicLong.class), CalendarConversion::toAtomicLong); + DEFAULT_FACTORY.put(pair(Number.class, AtomicLong.class), NumberConversion::toAtomicLong); DEFAULT_FACTORY.put(pair(Map.class, AtomicLong.class), (fromInstance, converter, options) -> converter.fromValueMap((Map) fromInstance, AtomicLong.class, null, options)); DEFAULT_FACTORY.put(pair(String.class, AtomicLong.class), StringConversion::stringToAtomicLong); @@ -738,17 +740,7 @@ private static void buildFactoryConversions() { long leastSigBits = bigInt.and(new BigInteger("FFFFFFFFFFFFFFFF", 16)).longValue(); return new UUID(mostSigBits, leastSigBits); }); - DEFAULT_FACTORY.put(pair(Map.class, UUID.class), (fromInstance, converter, options) -> { - Map map = (Map) fromInstance; - Object ret = converter.fromMap(map, "mostSigBits", long.class, options); - if (ret != NOPE) { - Object ret2 = converter.fromMap(map, "leastSigBits", long.class, options); - if (ret2 != NOPE) { - return new UUID((Long) ret, (Long) ret2); - } - } - throw new IllegalArgumentException("To convert Map to UUID, the Map must contain both 'mostSigBits' and 'leastSigBits' keys"); - }); + DEFAULT_FACTORY.put(pair(Map.class, UUID.class), MapConversion::toUUID); // Class conversions supported DEFAULT_FACTORY.put(pair(Void.class, Class.class), VoidConversion::toNull); @@ -810,7 +802,7 @@ private static void buildFactoryConversions() { return simpleDateFormat.format(((Calendar) fromInstance).getTime()); }); DEFAULT_FACTORY.put(pair(Number.class, String.class), Converter::toString); - DEFAULT_FACTORY.put(pair(Map.class, String.class), (fromInstance, converter, options) -> converter.fromValueMap((Map) fromInstance, String.class, null, options)); + DEFAULT_FACTORY.put(pair(Map.class, String.class), MapConversion::toString); DEFAULT_FACTORY.put(pair(Enum.class, String.class), (fromInstance, converter, options) -> ((Enum) fromInstance).name()); DEFAULT_FACTORY.put(pair(String.class, String.class), Converter::identity); DEFAULT_FACTORY.put(pair(Duration.class, String.class), Converter::toString); @@ -1267,7 +1259,7 @@ public Convert addConversion(Class source, Class target, Convert con target = toPrimitiveWrapperClass(target); return factory.put(pair(source, target), conversionFunction); } - + public static long localDateToMillis(LocalDate localDate, ZoneId zoneId) { return localDate.atStartOfDay(zoneId).toInstant().toEpochMilli(); } @@ -1279,7 +1271,7 @@ public static long localDateTimeToMillis(LocalDateTime localDateTime, ZoneId zon public static long zonedDateTimeToMillis(ZonedDateTime zonedDateTime) { return zonedDateTime.toInstant().toEpochMilli(); } - + /** * Given a primitive class, return the Wrapper class equivalent. */ diff --git a/src/main/java/com/cedarsoftware/util/convert/ConverterOptions.java b/src/main/java/com/cedarsoftware/util/convert/ConverterOptions.java index 42b28a843..f3c633a7a 100644 --- a/src/main/java/com/cedarsoftware/util/convert/ConverterOptions.java +++ b/src/main/java/com/cedarsoftware/util/convert/ConverterOptions.java @@ -66,12 +66,12 @@ public interface ConverterOptions { T getCustomOption(String name); /** - * @return zoneId to use for source conversion when on is not provided on the source (Date, Instant, etc.) + * @return TimeZone to use for source conversion when on is not provided on the source (Date, Instant, etc.) */ default TimeZone getSourceTimeZone() { return TimeZone.getTimeZone(this.getSourceZoneId()); } /** - * @return zoneId expected on the target when finished (only for types that support ZoneId or TimeZone) + * @return TimeZone expected on the target when finished (only for types that support ZoneId or TimeZone) */ default TimeZone getTargetTimeZone() { return TimeZone.getTimeZone(this.getTargetZoneId()); } } diff --git a/src/main/java/com/cedarsoftware/util/convert/DateConversion.java b/src/main/java/com/cedarsoftware/util/convert/DateConversion.java new file mode 100644 index 000000000..c4339d01a --- /dev/null +++ b/src/main/java/com/cedarsoftware/util/convert/DateConversion.java @@ -0,0 +1,18 @@ +package com.cedarsoftware.util.convert; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +public class DateConversion { + public static BigDecimal toBigDecimal(Object fromInstance, Converter converter, ConverterOptions options) { + Date from = (Date)fromInstance; + return BigDecimal.valueOf(from.getTime()); + } + + public static AtomicLong toAtomicLong(Object fromInstance, Converter converter, ConverterOptions options) { + Date from = (Date)fromInstance; + return new AtomicLong(from.getTime()); + } +} diff --git a/src/main/java/com/cedarsoftware/util/convert/MapConversion.java b/src/main/java/com/cedarsoftware/util/convert/MapConversion.java new file mode 100644 index 000000000..6aeed1f90 --- /dev/null +++ b/src/main/java/com/cedarsoftware/util/convert/MapConversion.java @@ -0,0 +1,90 @@ +package com.cedarsoftware.util.convert; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Map; +import java.util.UUID; + +public class MapConversion { + + private static final String V = "_v"; + private static final String VALUE = "value"; + + public static Object toUUID(Object fromInstance, Converter converter, ConverterOptions options) { + Map map = (Map) fromInstance; + + if (map.containsKey("mostSigBits") && map.containsKey("leastSigBits")) { + long most = converter.convert(map.get("mostSigBits"), long.class, options); + long least = converter.convert(map.get("leastSigBits"), long.class, options); + + return new UUID(most, least); + } + + throw new IllegalArgumentException("To convert Map to UUID, the Map must contain both 'mostSigBits' and 'leastSigBits' keys"); + } + + public static Byte toByte(Object fromInstance, Converter converter, ConverterOptions options) { + return fromMapValue(fromInstance, converter, options, Byte.class); + } + + public static Short toShort(Object fromInstance, Converter converter, ConverterOptions options) { + return fromMapValue(fromInstance, converter, options, Short.class); + } + + public static Integer toInt(Object fromInstance, Converter converter, ConverterOptions options) { + return fromMapValue(fromInstance, converter, options, Integer.class); + } + + public static Long toLong(Object fromInstance, Converter converter, ConverterOptions options) { + return fromMapValue(fromInstance, converter, options, Long.class); + } + + public static Float toFloat(Object fromInstance, Converter converter, ConverterOptions options) { + return fromMapValue(fromInstance, converter, options, Float.class); + } + + public static Double toDouble(Object fromInstance, Converter converter, ConverterOptions options) { + return fromMapValue(fromInstance, converter, options, Double.class); + } + + public static Boolean toBoolean(Object fromInstance, Converter converter, ConverterOptions options) { + return fromMapValue(fromInstance, converter, options, Boolean.class); + } + + public static BigDecimal toBigDecimal(Object fromInstance, Converter converter, ConverterOptions options) { + return fromMapValue(fromInstance, converter, options, BigDecimal.class); + } + + public static BigInteger toBigInteger(Object fromInstance, Converter converter, ConverterOptions options) { + return fromMapValue(fromInstance, converter, options, BigInteger.class); + } + + public static String toString(Object fromInstance, Converter converter, ConverterOptions options) { + return fromMapValue(fromInstance, converter, options, String.class); + } + + + public static T fromMapValue(Object fromInstance, Converter converter, ConverterOptions options, Class type) { + Map map = (Map) fromInstance; + + if (map.containsKey(V)) { + return converter.convert(map.get(V), type); + } + + if (map.containsKey(VALUE)) { + return converter.convert(map.get(VALUE), type); + } + + throw new IllegalArgumentException("To convert from Map to " + getShortName(type) + ", the map must include keys: '_v' or 'value' an associated value to convert from."); + } + + + private static T getConvertedValue(Map map, String key, Class type, Converter converter, ConverterOptions options) { + // NOPE STUFF? + return converter.convert(map.get(key), type, options); + } + + private static String getShortName(Class type) { + return java.sql.Date.class.equals(type) ? type.getName() : type.getSimpleName(); + } +} diff --git a/src/main/java/com/cedarsoftware/util/convert/NumberConversion.java b/src/main/java/com/cedarsoftware/util/convert/NumberConversion.java index 23e356aea..ff9f1038a 100644 --- a/src/main/java/com/cedarsoftware/util/convert/NumberConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/NumberConversion.java @@ -1,6 +1,10 @@ package com.cedarsoftware.util.convert; import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.sql.Timestamp; import java.time.Instant; import java.time.LocalDate; @@ -8,8 +12,6 @@ import java.time.ZonedDateTime; import java.util.Calendar; import java.util.Date; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; /** * @author Kenny Partlow (kpartlow@gmail.com) @@ -34,30 +36,82 @@ public static byte toByte(Object from, Converter converter, ConverterOptions opt return ((Number) from).byteValue(); } + public static Byte toByteZero(Object from, Converter converter, ConverterOptions options) { + return CommonValues.BYTE_ZERO; + } + + public static short toShort(Object from, Converter converter, ConverterOptions options) { return ((Number) from).shortValue(); } + public static Short toShortZero(Object from, Converter converter, ConverterOptions options) { + return CommonValues.SHORT_ZERO; + } + public static int toInt(Object from, Converter converter, ConverterOptions options) { return ((Number) from).intValue(); } + public static Integer toIntZero(Object from, Converter converter, ConverterOptions options) { + return CommonValues.INTEGER_ZERO; + } + + public static long toLong(Object from, Converter converter, ConverterOptions options) { return ((Number) from).longValue(); } + public static Long toLongZero(Object from, Converter converter, ConverterOptions options) { + return CommonValues.LONG_ZERO; + } + + public static float toFloat(Object from, Converter converter, ConverterOptions options) { return ((Number) from).floatValue(); } + public static Float toFloatZero(Object from, Converter converter, ConverterOptions options) { + return CommonValues.FLOAT_ZERO; + } + + public static double toDouble(Object from, Converter converter, ConverterOptions options) { return ((Number) from).doubleValue(); } - public static BigDecimal longToBigDecimal(Object from, Converter converter, ConverterOptions options) { + public static Double toDoubleZero(Object from, Converter converter, ConverterOptions options) { + return CommonValues.DOUBLE_ZERO; + } + + public static BigDecimal integerTypeToBigDecimal(Object from, Converter converter, ConverterOptions options) { return BigDecimal.valueOf(((Number) from).longValue()); } + public static AtomicLong toAtomicLong(Object from, Converter converter, ConverterOptions options) { + Number n = (Number)from; + return new AtomicLong(n.longValue()); + } + + public static AtomicInteger toAtomicInteger(Object from, Converter converter, ConverterOptions options) { + Number n = (Number)from; + return new AtomicInteger(n.intValue()); + } + + public static BigDecimal bigIntegerToBigDecimal(Object from, Converter converter, ConverterOptions options) { + return new BigDecimal((BigInteger)from); + } + + public static AtomicBoolean toAtomicBoolean(Object from, Converter converter, ConverterOptions options) { + Number number = (Number) from; + return new AtomicBoolean(number.longValue() != 0); + } + + public static BigDecimal floatingPointToBigDecimal(Object from, Converter converter, ConverterOptions options) { + Number n = (Number)from; + return BigDecimal.valueOf(n.doubleValue()); + } + public static boolean isIntTypeNotZero(Object from, Converter converter, ConverterOptions options) { return ((Number) from).longValue() != 0; } @@ -92,16 +146,6 @@ public static char numberToCharacter(Object from, Converter converter, Converter return numberToCharacter((Number) from); } - public static AtomicInteger numberToAtomicInteger(Object from, Converter converter, ConverterOptions options) { - Number number = (Number) from; - return new AtomicInteger(number.intValue()); - } - - public static AtomicLong numberToAtomicLong(Object from, Converter converter, ConverterOptions options) { - Number number = (Number) from; - return new AtomicLong(number.longValue()); - } - public static Date numberToDate(Object from, Converter converter, ConverterOptions options) { Number number = (Number) from; return new Date(number.longValue()); @@ -136,4 +180,4 @@ public static ZonedDateTime numberToZonedDateTime(Object from, Converter convert Number number = (Number) from; return Instant.ofEpochMilli(number.longValue()).atZone(options.getSourceZoneId()); } -} \ No newline at end of file +} diff --git a/src/main/java/com/cedarsoftware/util/convert/VoidConversion.java b/src/main/java/com/cedarsoftware/util/convert/VoidConversion.java index 247014d78..646b9b7c0 100644 --- a/src/main/java/com/cedarsoftware/util/convert/VoidConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/VoidConversion.java @@ -18,7 +18,16 @@ * limitations under the License. */ public class VoidConversion { + public static Object toNull(Object from, Converter converter, ConverterOptions options) { return null; } + + public static Boolean toBoolean(Object from, Converter converter, ConverterOptions options) { + return Boolean.FALSE; + } + + public static Character toChar(Object from, Converter converter, ConverterOptions options) { + return Character.MIN_VALUE; + } } diff --git a/src/test/java/com/cedarsoftware/util/convert/ConverterTest.java b/src/test/java/com/cedarsoftware/util/convert/ConverterTest.java index 541dad80d..039ea75bb 100644 --- a/src/test/java/com/cedarsoftware/util/convert/ConverterTest.java +++ b/src/test/java/com/cedarsoftware/util/convert/ConverterTest.java @@ -741,60 +741,88 @@ void testString_fromLocalDate() assertThat(converted).isEqualTo("2015-09-03"); } - @Test - void testBigDecimal() + + private static Stream testBigDecimalParams() { + return Stream.of( + Arguments.of("-32768", BigDecimal.valueOf(-32768L)), + Arguments.of("32767", BigDecimal.valueOf(32767L)), + Arguments.of(Byte.MIN_VALUE, BigDecimal.valueOf((-128L)), + Arguments.of(Byte.MAX_VALUE, BigDecimal.valueOf(127L)), + Arguments.of(Short.MIN_VALUE, BigDecimal.valueOf(-32768L)), + Arguments.of(Short.MAX_VALUE, BigDecimal.valueOf(32767L)), + Arguments.of(Integer.MIN_VALUE, BigDecimal.valueOf(-2147483648L)), + Arguments.of(Integer.MAX_VALUE, BigDecimal.valueOf(2147483647L)), + Arguments.of(Long.MIN_VALUE, BigDecimal.valueOf(-9223372036854775808L)), + Arguments.of(Long.MAX_VALUE, BigDecimal.valueOf(9223372036854775807L)), + Arguments.of(-128.0f, BigDecimal.valueOf(-128.0f)), + Arguments.of(127.0f, BigDecimal.valueOf(127.0f)), + Arguments.of(-128.0d, BigDecimal.valueOf(-128.0d))), + Arguments.of(127.0d, BigDecimal.valueOf(127.0d)), + Arguments.of( new BigDecimal("100"), new BigDecimal("100")), + Arguments.of( new BigInteger("120"), new BigDecimal("120")), + Arguments.of( new AtomicInteger(25), new BigDecimal(25)), + Arguments.of( new AtomicLong(100L), new BigDecimal(100)) + ); + } + + @ParameterizedTest + @MethodSource("testBigDecimalParams") + void testBigDecimal(Object value, BigDecimal expectedResult) { - Object o = converter.convert("", BigDecimal.class); - assertEquals(o, BigDecimal.ZERO); - BigDecimal x = this.converter.convert("-450000", BigDecimal.class); - assertEquals(new BigDecimal("-450000"), x); + BigDecimal converted = this.converter.convert(value, BigDecimal.class); + assertThat(converted).isEqualTo(expectedResult); + } - assertEquals(new BigDecimal("3.14"), this.converter.convert(new BigDecimal("3.14"), BigDecimal.class)); - assertEquals(new BigDecimal("8675309"), this.converter.convert(new BigInteger("8675309"), BigDecimal.class)); - assertEquals(new BigDecimal("75"), this.converter.convert((short) 75, BigDecimal.class)); - assertEquals(BigDecimal.ONE, this.converter.convert(true, BigDecimal.class)); - assertSame(BigDecimal.ONE, this.converter.convert(true, BigDecimal.class)); - assertEquals(BigDecimal.ZERO, this.converter.convert(false, BigDecimal.class)); - assertSame(BigDecimal.ZERO, this.converter.convert(false, BigDecimal.class)); + private static Stream testBigDecimalParams_withObjectsShouldBeSame() { + return Stream.of( + Arguments.of(new AtomicBoolean(true), BigDecimal.ONE), + Arguments.of(new AtomicBoolean(false), BigDecimal.ZERO), + Arguments.of(true, BigDecimal.ONE), + Arguments.of(false, BigDecimal.ZERO), + Arguments.of(Boolean.TRUE, BigDecimal.ONE), + Arguments.of(Boolean.FALSE, BigDecimal.ZERO), + Arguments.of("", BigDecimal.ZERO) + ); + } + @ParameterizedTest + @MethodSource("testBigDecimalParams") + void testBigDecimal_withBooleanTypes(Object value, BigDecimal expected) { + BigDecimal converted = this.converter.convert(value, BigDecimal.class); + assertThat(converted).isEqualTo(expected); + } + + @Test + void testBigDecimal_withDate() { Date now = new Date(); - BigDecimal now70 = new BigDecimal(now.getTime()); - assertEquals(now70, this.converter.convert(now, BigDecimal.class)); + BigDecimal bd = new BigDecimal(now.getTime()); + assertEquals(bd, this.converter.convert(now, BigDecimal.class)); + } + @Test + void testBigDecimal_witCalendar() { Calendar today = Calendar.getInstance(); - now70 = new BigDecimal(today.getTime().getTime()); - assertEquals(now70, this.converter.convert(today, BigDecimal.class)); - - assertEquals(new BigDecimal(25), this.converter.convert(new AtomicInteger(25), BigDecimal.class)); - assertEquals(new BigDecimal(100), this.converter.convert(new AtomicLong(100L), BigDecimal.class)); - assertEquals(BigDecimal.ONE, this.converter.convert(new AtomicBoolean(true), BigDecimal.class)); - assertEquals(BigDecimal.ZERO, this.converter.convert(new AtomicBoolean(false), BigDecimal.class)); + BigDecimal bd = new BigDecimal(today.getTime().getTime()); + assertEquals(bd, this.converter.convert(today, BigDecimal.class)); + } - assertEquals(converter.convert(BigDecimal.ZERO, Boolean.class), false); - assertEquals(converter.convert(BigDecimal.ONE, Boolean.class), true); - assertEquals(converter.convert(new BigDecimal("3.14159"), Boolean.class), true); - try - { - this.converter.convert(TimeZone.getDefault(), BigDecimal.class); - fail(); - } - catch (IllegalArgumentException e) - { - assertTrue(e.getMessage().toLowerCase().contains("unsupported conversion, source type [zoneinfo")); - } + private static Stream testConvertToBigDecimalParams_withIllegalArguments() { + return Stream.of( + Arguments.of("45badNumber", "not parseable"), + Arguments.of(ZoneId.systemDefault(), "Unsupported conversion"), + Arguments.of( TimeZone.getDefault(), "Unsupported conversion")); + } - try - { - this.converter.convert("45badNumber", BigDecimal.class); - fail(); - } - catch (IllegalArgumentException e) - { - assertTrue(e.getMessage().toLowerCase().contains("value: 45badnumber not parseable as a bigdecimal value")); - } + @ParameterizedTest + @MethodSource("testConvertToBigDecimalParams_withIllegalArguments") + void testConvertToBigDecimal_withIllegalArguments(Object value, String partialMessage) { + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> this.converter.convert(value, AtomicLong.class)) + .withMessageContaining(partialMessage); } + @Test void testBigInteger() { @@ -2167,7 +2195,7 @@ void testConvert2() void testNullType() { assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> this.converter.convert("123", null)) - // No Message was coming through here and receiving NullPointerException -- changed to convention over in convert -- hopefully that's what you had in mind. + // TOTO: in case you didn't see, No Message was coming through here and receiving NullPointerException -- changed to convention over in convert -- hopefully that's what you had in mind. .withMessageContaining("toType cannot be null"); }