From f3c18b9c3cbd3e16f71424a6b6aff4bb86359f45 Mon Sep 17 00:00:00 2001 From: Ken Partlow Date: Sun, 14 Jan 2024 23:59:32 -0500 Subject: [PATCH] Adding Temporal Conversion Tests LocalDate conversions --- .../com/cedarsoftware/util/Converter.java | 10 +- .../util/convert/AtomicBooleanConversion.java | 6 + .../util/convert/BooleanConversion.java | 11 + .../util/convert/CalendarConversion.java | 79 +- .../util/convert/CharacterConversion.java | 63 +- .../cedarsoftware/util/convert/Converter.java | 248 +-- .../util/convert/ConverterOptions.java | 32 +- .../util/convert/DateConversion.java | 61 +- .../util/convert/InstantConversion.java | 67 + .../util/convert/LocalDateConversion.java | 81 + .../util/convert/LocalDateTimeConversion.java | 70 + .../util/convert/MapConversion.java | 84 +- .../util/convert/NumberConversion.java | 84 +- .../util/convert/StringConversion.java | 6 +- .../util/convert/ZonedDateTimeConversion.java | 76 + .../util/convert/ConverterTest.java | 1595 +++++++++++------ .../util/convert/DateConversionTests.java | 19 + 17 files changed, 1804 insertions(+), 788 deletions(-) create mode 100644 src/main/java/com/cedarsoftware/util/convert/InstantConversion.java create mode 100644 src/main/java/com/cedarsoftware/util/convert/LocalDateConversion.java create mode 100644 src/main/java/com/cedarsoftware/util/convert/LocalDateTimeConversion.java create mode 100644 src/main/java/com/cedarsoftware/util/convert/ZonedDateTimeConversion.java create mode 100644 src/test/java/com/cedarsoftware/util/convert/DateConversionTests.java diff --git a/src/main/java/com/cedarsoftware/util/Converter.java b/src/main/java/com/cedarsoftware/util/Converter.java index a6f1c534..be491e56 100644 --- a/src/main/java/com/cedarsoftware/util/Converter.java +++ b/src/main/java/com/cedarsoftware/util/Converter.java @@ -457,29 +457,33 @@ public static AtomicBoolean convertToAtomicBoolean(Object fromInstance) * @param localDate A Java LocalDate * @return a long representing the localDate as the number of milliseconds since the * number of milliseconds since Jan 1, 1970 + * @deprecated use convert(localDate, long.class); */ + public static long localDateToMillis(LocalDate localDate) { - return com.cedarsoftware.util.convert.Converter.localDateToMillis(localDate, instance.getOptions().getSourceZoneId()); + return instance.convert(localDate, long.class); } /** * @param localDateTime A Java LocalDateTime * @return a long representing the localDateTime as the number of milliseconds since the * number of milliseconds since Jan 1, 1970 + * @deprecated use convert(localDateTime, long.class); */ public static long localDateTimeToMillis(LocalDateTime localDateTime) { - return com.cedarsoftware.util.convert.Converter.localDateTimeToMillis(localDateTime, instance.getOptions().getSourceZoneId()); + return instance.convert(localDateTime, long.class); } /** * @param zonedDateTime A Java ZonedDateTime * @return a long representing the zonedDateTime as the number of milliseconds since the * number of milliseconds since Jan 1, 1970 + * @deprecated use convert(zonedDateTime, long.class); */ public static long zonedDateTimeToMillis(ZonedDateTime zonedDateTime) { - return com.cedarsoftware.util.convert.Converter.zonedDateTimeToMillis(zonedDateTime); + return instance.convert(zonedDateTime, long.class); } } diff --git a/src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversion.java b/src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversion.java index 7f157e47..b5730345 100644 --- a/src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversion.java @@ -1,6 +1,7 @@ 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; @@ -61,4 +62,9 @@ static BigDecimal toBigDecimal(Object from, Converter converter, ConverterOption AtomicBoolean b = (AtomicBoolean) from; return b.get() ? BigDecimal.ONE : BigDecimal.ZERO; } + + public static BigInteger toBigInteger(Object from, Converter converter, ConverterOptions options) { + AtomicBoolean b = (AtomicBoolean) from; + return b.get() ? BigInteger.ONE : BigInteger.ZERO; + } } diff --git a/src/main/java/com/cedarsoftware/util/convert/BooleanConversion.java b/src/main/java/com/cedarsoftware/util/convert/BooleanConversion.java index 855837ef..44b6b6fa 100644 --- a/src/main/java/com/cedarsoftware/util/convert/BooleanConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/BooleanConversion.java @@ -1,7 +1,9 @@ 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; /** @@ -38,6 +40,11 @@ static Integer toInteger(Object from, Converter converter, ConverterOptions opti return b ? CommonValues.INTEGER_ONE : CommonValues.INTEGER_ZERO; } + static AtomicInteger toAtomicInteger(Object from, Converter converter, ConverterOptions options) { + Boolean b = (Boolean) from; + return new AtomicInteger(b ? 1 : 0); + } + static AtomicLong toAtomicLong(Object from, Converter converter, ConverterOptions options) { Boolean b = (Boolean) from; return new AtomicLong(b ? 1 : 0); @@ -58,6 +65,10 @@ static BigDecimal toBigDecimal(Object from, Converter converter, ConverterOption return b ? BigDecimal.ONE : BigDecimal.ZERO; } + static BigInteger toBigInteger(Object from, Converter converter, ConverterOptions options) { + return ((Boolean)from) ? BigInteger.ONE : BigInteger.ZERO; + } + static Float toFloat(Object from, Converter converter, ConverterOptions options) { Boolean b = (Boolean) from; return b ? CommonValues.FLOAT_ONE : CommonValues.FLOAT_ZERO; diff --git a/src/main/java/com/cedarsoftware/util/convert/CalendarConversion.java b/src/main/java/com/cedarsoftware/util/convert/CalendarConversion.java index d613d439..7f72de01 100644 --- a/src/main/java/com/cedarsoftware/util/convert/CalendarConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/CalendarConversion.java @@ -2,28 +2,93 @@ import java.math.BigDecimal; import java.math.BigInteger; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; import java.util.Calendar; import java.util.Date; +import java.util.GregorianCalendar; import java.util.concurrent.atomic.AtomicLong; public class CalendarConversion { + + static Date toDate(Object fromInstance) { + return ((Calendar)fromInstance).getTime(); + } + + static long toLong(Object fromInstance) { + return toDate(fromInstance).getTime(); + } + + static Instant toInstant(Object fromInstance) { + return ((Calendar)fromInstance).toInstant(); + } + + static ZonedDateTime toZonedDateTime(Object fromInstance, ConverterOptions options) { + return toInstant(fromInstance).atZone(options.getZoneId()); + } + + static ZonedDateTime toZonedDateTime(Object fromInstance, Converter converter, ConverterOptions options) { + return toZonedDateTime(fromInstance, options); + } + + + static Long toLong(Object fromInstance, Converter converter, ConverterOptions options) { + return toLong(fromInstance); + } + static Date toDate(Object fromInstance, Converter converter, ConverterOptions options) { - Calendar from = (Calendar)fromInstance; - return from.getTime(); + return toDate(fromInstance); + } + + static java.sql.Date toSqlDate(Object fromInstance, Converter converter, ConverterOptions options) { + return new java.sql.Date(toLong(fromInstance)); + } + + static Timestamp toTimestamp(Object fromInstance, Converter converter, ConverterOptions options) { + return new Timestamp(toLong(fromInstance)); } static AtomicLong toAtomicLong(Object fromInstance, Converter converter, ConverterOptions options) { - Calendar from = (Calendar)fromInstance; - return new AtomicLong(from.getTime().getTime()); + return new AtomicLong(toLong(fromInstance)); + } + + static Instant toInstant(Object fromInstance, Converter converter, ConverterOptions options) { + return toInstant(fromInstance); + } + + static LocalDateTime toLocalDateTime(Object fromInstance, Converter converter, ConverterOptions options) { + return toZonedDateTime(fromInstance, options).toLocalDateTime(); + } + + static LocalDate toLocalDate(Object fromInstance, Converter converter, ConverterOptions options) { + return toZonedDateTime(fromInstance, options).toLocalDate(); } static BigDecimal toBigDecimal(Object fromInstance, Converter converter, ConverterOptions options) { - Calendar from = (Calendar)fromInstance; - return BigDecimal.valueOf(from.getTime().getTime()); + return BigDecimal.valueOf(toLong(fromInstance)); } static BigInteger toBigInteger(Object fromInstance, Converter converter, ConverterOptions options) { + return BigInteger.valueOf(toLong(fromInstance)); + } + + static Calendar clone(Object fromInstance, Converter converter, ConverterOptions options) { Calendar from = (Calendar)fromInstance; - return BigInteger.valueOf(from.getTime().getTime()); + // mutable class, so clone it. + return (Calendar)from.clone(); + } + + static Calendar create(long epochMilli, ConverterOptions options) { + Calendar cal = Calendar.getInstance(options.getTimeZone()); + cal.clear(); + cal.setTimeInMillis(epochMilli); + return cal; + } + + static Calendar create(ZonedDateTime time, ConverterOptions options) { + return GregorianCalendar.from(time); } } diff --git a/src/main/java/com/cedarsoftware/util/convert/CharacterConversion.java b/src/main/java/com/cedarsoftware/util/convert/CharacterConversion.java index 6d708ca0..25b5aecd 100644 --- a/src/main/java/com/cedarsoftware/util/convert/CharacterConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/CharacterConversion.java @@ -1,16 +1,73 @@ package com.cedarsoftware.util.convert; +import com.cedarsoftware.util.CaseInsensitiveMap; +import com.cedarsoftware.util.CollectionUtilities; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + public class CharacterConversion { + + private CharacterConversion() { + } + + static boolean toBoolean(Object from) { + char c = (char) from; + return (c == 1) || (c == 't') || (c == 'T') || (c == '1'); + } + + static boolean toBoolean(Object from, Converter converter, ConverterOptions options) { - Character c = (Character) from; - return c != CommonValues.CHARACTER_ZERO; + return toBoolean(from); } - static double toDouble(Object from, Converter converter, ConverterOptions options) { + // downcasting -- not always a safe conversino + static byte toByte(Object from, Converter converter, ConverterOptions options) { + return (byte) (char) from; + } + + static short toShort(Object from, Converter converter, ConverterOptions options) { + return (short) (char) from; + } + + static int toInt(Object from, Converter converter, ConverterOptions options) { + return (char) from; + } + + static long toLong(Object from, Converter converter, ConverterOptions options) { return (char) from; } static float toFloat(Object from, Converter converter, ConverterOptions options) { return (char) from; } + + static double toDouble(Object from, Converter converter, ConverterOptions options) { + return (char) from; + } + + static AtomicInteger toAtomicInteger(Object from, Converter converter, ConverterOptions options) { + return new AtomicInteger((char) from); + } + + static AtomicLong toAtomicLong(Object from, Converter converter, ConverterOptions options) { + return new AtomicLong((char) from); + } + + static AtomicBoolean toAtomicBoolean(Object from, Converter converter, ConverterOptions options) { + return new AtomicBoolean(toBoolean(from)); + } + + static BigInteger toBigInteger(Object from, Converter converter, ConverterOptions options) { + return BigInteger.valueOf((char) from); + } + + static BigDecimal toBigDecimal(Object from, Converter converter, ConverterOptions options) { + return BigDecimal.valueOf((char) from); + } } diff --git a/src/main/java/com/cedarsoftware/util/convert/Converter.java b/src/main/java/com/cedarsoftware/util/convert/Converter.java index 3bd16b4f..5c4ea206 100644 --- a/src/main/java/com/cedarsoftware/util/convert/Converter.java +++ b/src/main/java/com/cedarsoftware/util/convert/Converter.java @@ -117,7 +117,7 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(Float.class, Byte.class), NumberConversion::toByte); DEFAULT_FACTORY.put(pair(Double.class, Byte.class), NumberConversion::toByte); 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(Character.class, Byte.class), CharacterConversion::toByte); DEFAULT_FACTORY.put(pair(Calendar.class, Byte.class), NumberConversion::toByte); DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Byte.class), AtomicBooleanConversion::toByte); DEFAULT_FACTORY.put(pair(AtomicInteger.class, Byte.class), NumberConversion::toByte); @@ -138,7 +138,7 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(Float.class, Short.class), NumberConversion::toShort); 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(Character.class, Short.class), CharacterConversion::toShort); 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); @@ -159,7 +159,7 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(Float.class, Integer.class), NumberConversion::toInt); 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(Character.class, Integer.class), CharacterConversion::toInt); 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); @@ -180,19 +180,20 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(Float.class, Long.class), NumberConversion::toLong); 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(Character.class, Long.class), CharacterConversion::toLong); 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); DEFAULT_FACTORY.put(pair(BigDecimal.class, Long.class), NumberConversion::toLong); - DEFAULT_FACTORY.put(pair(Date.class, Long.class), (fromInstance, converter, options) -> ((Date) fromInstance).getTime()); - DEFAULT_FACTORY.put(pair(java.sql.Date.class, Long.class), (fromInstance, converter, options) -> ((Date) fromInstance).getTime()); - DEFAULT_FACTORY.put(pair(Timestamp.class, Long.class), (fromInstance, converter, options) -> ((Date) fromInstance).getTime()); - DEFAULT_FACTORY.put(pair(LocalDate.class, Long.class), (fromInstance, converter, options) -> ((LocalDate) fromInstance).toEpochDay()); - DEFAULT_FACTORY.put(pair(LocalDateTime.class, Long.class), (fromInstance, converter, options) -> localDateTimeToMillis((LocalDateTime) fromInstance, options.getSourceZoneId())); - 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(Date.class, Long.class), DateConversion::toLong); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, Long.class), DateConversion::toLong); + DEFAULT_FACTORY.put(pair(Timestamp.class, Long.class), DateConversion::toLong); + DEFAULT_FACTORY.put(pair(Instant.class, Long.class), InstantConversion::toLong); + DEFAULT_FACTORY.put(pair(LocalDate.class, Long.class), LocalDateConversion::toLong); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, Long.class), LocalDateTimeConversion::toLong); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, Long.class), ZonedDateTimeConversion::toLong); + DEFAULT_FACTORY.put(pair(Calendar.class, Long.class), CalendarConversion::toLong); DEFAULT_FACTORY.put(pair(Number.class, Long.class), NumberConversion::toLong); DEFAULT_FACTORY.put(pair(Map.class, Long.class), MapConversion::toLong); DEFAULT_FACTORY.put(pair(String.class, Long.class), StringConversion::toLong); @@ -208,7 +209,8 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(Double.class, Float.class), NumberConversion::toFloat); DEFAULT_FACTORY.put(pair(Boolean.class, Float.class), BooleanConversion::toFloat); DEFAULT_FACTORY.put(pair(Character.class, Float.class), CharacterConversion::toFloat); - DEFAULT_FACTORY.put(pair(LocalDate.class, Float.class), (fromInstance, converter, options) -> ((LocalDate) fromInstance).toEpochDay()); + DEFAULT_FACTORY.put(pair(Instant.class, Float.class), InstantConversion::toFloat); + DEFAULT_FACTORY.put(pair(LocalDate.class, Float.class), LocalDateConversion::toLong); DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Float.class), AtomicBooleanConversion::toFloat); DEFAULT_FACTORY.put(pair(AtomicInteger.class, Float.class), NumberConversion::toFloat); DEFAULT_FACTORY.put(pair(AtomicLong.class, Float.class), NumberConversion::toFloat); @@ -219,7 +221,7 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(String.class, Float.class), StringConversion::toFloat); // Double/double conversions supported - DEFAULT_FACTORY.put(pair(Void.class, double.class), (fromInstance, converter, options) -> 0.0d); + DEFAULT_FACTORY.put(pair(Void.class, double.class), NumberConversion::toDoubleZero); DEFAULT_FACTORY.put(pair(Void.class, Double.class), VoidConversion::toNull); DEFAULT_FACTORY.put(pair(Byte.class, Double.class), NumberConversion::toDouble); DEFAULT_FACTORY.put(pair(Short.class, Double.class), NumberConversion::toDouble); @@ -229,12 +231,13 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(Double.class, Double.class), Converter::identity); DEFAULT_FACTORY.put(pair(Boolean.class, Double.class), BooleanConversion::toDouble); DEFAULT_FACTORY.put(pair(Character.class, Double.class), CharacterConversion::toDouble); - DEFAULT_FACTORY.put(pair(LocalDate.class, Double.class), (fromInstance, converter, options) -> (double) ((LocalDate) fromInstance).toEpochDay()); - DEFAULT_FACTORY.put(pair(LocalDateTime.class, Double.class), (fromInstance, converter, options) -> (double) localDateTimeToMillis((LocalDateTime) fromInstance, options.getSourceZoneId())); - DEFAULT_FACTORY.put(pair(ZonedDateTime.class, Double.class), (fromInstance, converter, options) -> (double) zonedDateTimeToMillis((ZonedDateTime) fromInstance)); - DEFAULT_FACTORY.put(pair(Date.class, Double.class), (fromInstance, converter, options) -> (double) ((Date) fromInstance).getTime()); - DEFAULT_FACTORY.put(pair(java.sql.Date.class, Double.class), (fromInstance, converter, options) -> (double) ((Date) fromInstance).getTime()); - DEFAULT_FACTORY.put(pair(Timestamp.class, Double.class), (fromInstance, converter, options) -> (double) ((Date) fromInstance).getTime()); + DEFAULT_FACTORY.put(pair(Instant.class, Double.class), InstantConversion::toLong); + DEFAULT_FACTORY.put(pair(LocalDate.class, Double.class), LocalDateConversion::toLong); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, Double.class), LocalDateTimeConversion::toLong); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, Double.class), ZonedDateTimeConversion::toLong); + DEFAULT_FACTORY.put(pair(Date.class, Double.class), DateConversion::toLong); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, Double.class), DateConversion::toLong); + DEFAULT_FACTORY.put(pair(Timestamp.class, Double.class), DateConversion::toLong); DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Double.class), AtomicBooleanConversion::toDouble); DEFAULT_FACTORY.put(pair(AtomicInteger.class, Double.class), NumberConversion::toDouble); DEFAULT_FACTORY.put(pair(AtomicLong.class, Double.class), NumberConversion::toDouble); @@ -287,25 +290,26 @@ private static void buildFactoryConversions() { // BigInteger versions supported DEFAULT_FACTORY.put(pair(Void.class, BigInteger.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Byte.class, BigInteger.class), (fromInstance, converter, options) -> BigInteger.valueOf((byte) fromInstance)); - DEFAULT_FACTORY.put(pair(Short.class, BigInteger.class), (fromInstance, converter, options) -> BigInteger.valueOf((short) fromInstance)); - DEFAULT_FACTORY.put(pair(Integer.class, BigInteger.class), (fromInstance, converter, options) -> BigInteger.valueOf((int) fromInstance)); - DEFAULT_FACTORY.put(pair(Long.class, BigInteger.class), (fromInstance, converter, options) -> BigInteger.valueOf((long) fromInstance)); + DEFAULT_FACTORY.put(pair(Byte.class, BigInteger.class), NumberConversion::integerTypeToBigInteger); + DEFAULT_FACTORY.put(pair(Short.class, BigInteger.class), NumberConversion::integerTypeToBigInteger); + DEFAULT_FACTORY.put(pair(Integer.class, BigInteger.class), NumberConversion::integerTypeToBigInteger); + DEFAULT_FACTORY.put(pair(Long.class, BigInteger.class), NumberConversion::integerTypeToBigInteger); DEFAULT_FACTORY.put(pair(Float.class, BigInteger.class), (fromInstance, converter, options) -> new BigInteger(String.format("%.0f", (float) fromInstance))); DEFAULT_FACTORY.put(pair(Double.class, BigInteger.class), (fromInstance, converter, options) -> new BigInteger(String.format("%.0f", (double) fromInstance))); - DEFAULT_FACTORY.put(pair(Boolean.class, BigInteger.class), (fromInstance, converter, options) -> (Boolean) fromInstance ? BigInteger.ONE : BigInteger.ZERO); - DEFAULT_FACTORY.put(pair(Character.class, BigInteger.class), (fromInstance, converter, options) -> BigInteger.valueOf(((char) fromInstance))); + DEFAULT_FACTORY.put(pair(Boolean.class, BigInteger.class), BooleanConversion::toBigInteger); + DEFAULT_FACTORY.put(pair(Character.class, BigInteger.class), CharacterConversion::toBigInteger); DEFAULT_FACTORY.put(pair(BigInteger.class, BigInteger.class), Converter::identity); - DEFAULT_FACTORY.put(pair(BigDecimal.class, BigInteger.class), (fromInstance, converter, options) -> ((BigDecimal) fromInstance).toBigInteger()); - DEFAULT_FACTORY.put(pair(AtomicBoolean.class, BigInteger.class), (fromInstance, converter, options) -> ((AtomicBoolean) fromInstance).get() ? BigInteger.ONE : BigInteger.ZERO); - DEFAULT_FACTORY.put(pair(AtomicInteger.class, BigInteger.class), (fromInstance, converter, options) -> BigInteger.valueOf(((Number) fromInstance).intValue())); - DEFAULT_FACTORY.put(pair(AtomicLong.class, BigInteger.class), (fromInstance, converter, options) -> BigInteger.valueOf(((Number) fromInstance).longValue())); - DEFAULT_FACTORY.put(pair(Date.class, BigInteger.class), (fromInstance, converter, options) -> BigInteger.valueOf(((Date) fromInstance).getTime())); - DEFAULT_FACTORY.put(pair(java.sql.Date.class, BigInteger.class), (fromInstance, converter, options) -> BigInteger.valueOf(((Date) fromInstance).getTime())); - DEFAULT_FACTORY.put(pair(Timestamp.class, BigInteger.class), (fromInstance, converter, options) -> BigInteger.valueOf(((Date) fromInstance).getTime())); - DEFAULT_FACTORY.put(pair(LocalDate.class, BigInteger.class), (fromInstance, converter, options) -> BigInteger.valueOf(((LocalDate) fromInstance).toEpochDay())); - DEFAULT_FACTORY.put(pair(LocalDateTime.class, BigInteger.class), (fromInstance, converter, options) -> BigInteger.valueOf(localDateTimeToMillis((LocalDateTime) fromInstance, options.getSourceZoneId()))); - DEFAULT_FACTORY.put(pair(ZonedDateTime.class, BigInteger.class), (fromInstance, converter, options) -> BigInteger.valueOf(zonedDateTimeToMillis((ZonedDateTime) fromInstance))); + DEFAULT_FACTORY.put(pair(BigDecimal.class, BigInteger.class), NumberConversion::bigDecimalToBigInteger); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, BigInteger.class), AtomicBooleanConversion::toBigInteger); + DEFAULT_FACTORY.put(pair(AtomicInteger.class, BigInteger.class), NumberConversion::integerTypeToBigInteger); + DEFAULT_FACTORY.put(pair(AtomicLong.class, BigInteger.class), NumberConversion::integerTypeToBigInteger); + DEFAULT_FACTORY.put(pair(Date.class, BigInteger.class), DateConversion::toBigInteger); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, BigInteger.class), DateConversion::toBigInteger); + DEFAULT_FACTORY.put(pair(Timestamp.class, BigInteger.class), DateConversion::toBigInteger); + DEFAULT_FACTORY.put(pair(Instant.class, BigInteger.class), InstantConversion::toBigInteger); + DEFAULT_FACTORY.put(pair(LocalDate.class, BigInteger.class), LocalDateConversion::toBigInteger); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, BigInteger.class), LocalDateTimeConversion::toBigInteger); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, BigInteger.class), ZonedDateTimeConversion::toBigInteger); DEFAULT_FACTORY.put(pair(UUID.class, BigInteger.class), (fromInstance, converter, options) -> { UUID uuid = (UUID) fromInstance; BigInteger mostSignificant = BigInteger.valueOf(uuid.getMostSignificantBits()); @@ -329,7 +333,7 @@ private static void buildFactoryConversions() { 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(Character.class, BigDecimal.class), CharacterConversion::toBigDecimal); DEFAULT_FACTORY.put(pair(BigDecimal.class, BigDecimal.class), Converter::identity); DEFAULT_FACTORY.put(pair(BigInteger.class, BigDecimal.class), NumberConversion::bigIntegerToBigDecimal); DEFAULT_FACTORY.put(pair(AtomicBoolean.class, BigDecimal.class), AtomicBooleanConversion::toBigDecimal); @@ -338,9 +342,10 @@ private static void buildFactoryConversions() { 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))); + DEFAULT_FACTORY.put(pair(Instant.class, BigDecimal.class), InstantConversion::toBigDecimal); + DEFAULT_FACTORY.put(pair(LocalDate.class, BigDecimal.class), LocalDateConversion::toBigDecimal); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, BigDecimal.class), LocalDateTimeConversion::toBigDecimal); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, BigDecimal.class), ZonedDateTimeConversion::toBigDecimal); DEFAULT_FACTORY.put(pair(UUID.class, BigDecimal.class), (fromInstance, converter, options) -> { UUID uuid = (UUID) fromInstance; BigInteger mostSignificant = BigInteger.valueOf(uuid.getMostSignificantBits()); @@ -362,7 +367,7 @@ private static void buildFactoryConversions() { 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), BooleanConversion::toAtomicBoolean); - DEFAULT_FACTORY.put(pair(Character.class, AtomicBoolean.class), (fromInstance, converter, options) -> new AtomicBoolean((char) fromInstance > 0)); + DEFAULT_FACTORY.put(pair(Character.class, AtomicBoolean.class), CharacterConversion::toAtomicBoolean); 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 @@ -380,14 +385,14 @@ private static void buildFactoryConversions() { 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(Boolean.class, AtomicInteger.class), BooleanConversion::toAtomicInteger); + DEFAULT_FACTORY.put(pair(Character.class, AtomicInteger.class), CharacterConversion::toBigInteger); 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(AtomicBoolean.class, AtomicInteger.class), AtomicBooleanConversion::toAtomicInteger); 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(LocalDate.class, AtomicInteger.class), LocalDateConversion::toAtomicLong); DEFAULT_FACTORY.put(pair(Number.class, AtomicBoolean.class), NumberConversion::toAtomicInteger); DEFAULT_FACTORY.put(pair(Map.class, AtomicInteger.class), MapConversion::toAtomicInteger); DEFAULT_FACTORY.put(pair(String.class, AtomicInteger.class), StringConversion::toAtomicInteger); @@ -410,9 +415,10 @@ private static void buildFactoryConversions() { 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(Instant.class, AtomicLong.class), InstantConversion::toAtomicLong); + DEFAULT_FACTORY.put(pair(LocalDate.class, AtomicLong.class), LocalDateConversion::toAtomicLong); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, AtomicLong.class), LocalDateTimeConversion::toAtomicLong); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, AtomicLong.class), ZonedDateTimeConversion::toAtomicLong); 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), MapConversion::toAtomicLong); @@ -428,9 +434,10 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(Date.class, Date.class), (fromInstance, converter, options) -> new Date(((Date) fromInstance).getTime())); DEFAULT_FACTORY.put(pair(java.sql.Date.class, Date.class), (fromInstance, converter, options) -> new Date(((Date) fromInstance).getTime())); DEFAULT_FACTORY.put(pair(Timestamp.class, Date.class), (fromInstance, converter, options) -> new Date(((Date) fromInstance).getTime())); - DEFAULT_FACTORY.put(pair(LocalDate.class, Date.class), (fromInstance, converter, options) -> new Date(localDateToMillis((LocalDate) fromInstance, options.getSourceZoneId()))); - DEFAULT_FACTORY.put(pair(LocalDateTime.class, Date.class), (fromInstance, converter, options) -> new Date(localDateTimeToMillis((LocalDateTime) fromInstance, options.getSourceZoneId()))); - DEFAULT_FACTORY.put(pair(ZonedDateTime.class, Date.class), (fromInstance, converter, options) -> new Date(zonedDateTimeToMillis((ZonedDateTime) fromInstance))); + DEFAULT_FACTORY.put(pair(Instant.class, Date.class), InstantConversion::toDate); + DEFAULT_FACTORY.put(pair(LocalDate.class, Date.class), LocalDateConversion::toDate); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, Date.class), LocalDateTimeConversion::toDate); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, Date.class), ZonedDateTimeConversion::toDate); DEFAULT_FACTORY.put(pair(Calendar.class, Date.class), CalendarConversion::toDate); DEFAULT_FACTORY.put(pair(Number.class, Date.class), NumberConversion::toDate); DEFAULT_FACTORY.put(pair(Map.class, Date.class), (fromInstance, converter, options) -> { @@ -450,23 +457,15 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(BigInteger.class, java.sql.Date.class), NumberConversion::toSqlDate); DEFAULT_FACTORY.put(pair(BigDecimal.class, java.sql.Date.class), NumberConversion::toSqlDate); DEFAULT_FACTORY.put(pair(AtomicLong.class, java.sql.Date.class), NumberConversion::toSqlDate); - // why not use identity? (no conversion needed) - DEFAULT_FACTORY.put(pair(java.sql.Date.class, java.sql.Date.class), (fromInstance, converter, options) -> new java.sql.Date(((java.sql.Date) fromInstance).getTime())); // java.sql.Date is mutable + DEFAULT_FACTORY.put(pair(java.sql.Date.class, java.sql.Date.class), DateConversion::toSqlDate); // mutable type (creates new) DEFAULT_FACTORY.put(pair(Date.class, java.sql.Date.class), DateConversion::toSqlDate); - DEFAULT_FACTORY.put(pair(Timestamp.class, java.sql.Date.class), (fromInstance, converter, options) -> new java.sql.Date(((Date) fromInstance).getTime())); - DEFAULT_FACTORY.put(pair(LocalDate.class, java.sql.Date.class), (fromInstance, converter, options) -> new java.sql.Date(localDateToMillis((LocalDate) fromInstance, options.getSourceZoneId()))); - DEFAULT_FACTORY.put(pair(LocalDateTime.class, java.sql.Date.class), (fromInstance, converter, options) -> new java.sql.Date(localDateTimeToMillis((LocalDateTime) fromInstance, options.getSourceZoneId()))); - DEFAULT_FACTORY.put(pair(ZonedDateTime.class, java.sql.Date.class), (fromInstance, converter, options) -> new java.sql.Date(zonedDateTimeToMillis((ZonedDateTime) fromInstance))); - DEFAULT_FACTORY.put(pair(Calendar.class, java.sql.Date.class), (fromInstance, converter, options) -> new java.sql.Date(((Calendar) fromInstance).getTime().getTime())); + DEFAULT_FACTORY.put(pair(Timestamp.class, java.sql.Date.class), DateConversion::toSqlDate); + DEFAULT_FACTORY.put(pair(LocalDate.class, java.sql.Date.class), LocalDateConversion::toSqlDate); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, java.sql.Date.class), LocalDateTimeConversion::toSqlDate); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, java.sql.Date.class), ZonedDateTimeConversion::toSqlDate); + DEFAULT_FACTORY.put(pair(Calendar.class, java.sql.Date.class), CalendarConversion::toSqlDate); DEFAULT_FACTORY.put(pair(Number.class, java.sql.Date.class), NumberConversion::toSqlDate); - DEFAULT_FACTORY.put(pair(Map.class, java.sql.Date.class), (fromInstance, converter, options) -> { - Map map = (Map) fromInstance; - if (map.containsKey("time")) { - return converter.convert(map.get("time"), java.sql.Date.class, options); - } else { - return converter.fromValueMap((Map) fromInstance, java.sql.Date.class, CollectionUtilities.setOf("time"), options); - } - }); + DEFAULT_FACTORY.put(pair(Map.class, java.sql.Date.class), MapConversion::toSqlDate); DEFAULT_FACTORY.put(pair(String.class, java.sql.Date.class), StringConversion::toSqlDate); // Timestamp conversions supported @@ -476,13 +475,13 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(BigInteger.class, Timestamp.class), NumberConversion::toTimestamp); DEFAULT_FACTORY.put(pair(BigDecimal.class, Timestamp.class), NumberConversion::toTimestamp); DEFAULT_FACTORY.put(pair(AtomicLong.class, Timestamp.class), NumberConversion::toTimestamp); - DEFAULT_FACTORY.put(pair(Timestamp.class, Timestamp.class), (fromInstance, converter, options) -> new Timestamp(((Timestamp) fromInstance).getTime())); - DEFAULT_FACTORY.put(pair(java.sql.Date.class, Timestamp.class), (fromInstance, converter, options) -> new Timestamp(((Date) fromInstance).getTime())); - DEFAULT_FACTORY.put(pair(Date.class, Timestamp.class), (fromInstance, converter, options) -> new Timestamp(((Date) fromInstance).getTime())); - DEFAULT_FACTORY.put(pair(LocalDate.class, Timestamp.class), (fromInstance, converter, options) -> new Timestamp(localDateToMillis((LocalDate) fromInstance, options.getSourceZoneId()))); - DEFAULT_FACTORY.put(pair(LocalDateTime.class, Timestamp.class), (fromInstance, converter, options) -> new Timestamp(localDateTimeToMillis((LocalDateTime) fromInstance, options.getSourceZoneId()))); - DEFAULT_FACTORY.put(pair(ZonedDateTime.class, Timestamp.class), (fromInstance, converter, options) -> new Timestamp(zonedDateTimeToMillis((ZonedDateTime) fromInstance))); - DEFAULT_FACTORY.put(pair(Calendar.class, Timestamp.class), (fromInstance, converter, options) -> new Timestamp(((Calendar) fromInstance).getTime().getTime())); + DEFAULT_FACTORY.put(pair(Timestamp.class, Timestamp.class), DateConversion::toTimestamp); //mutable type (creates new) + DEFAULT_FACTORY.put(pair(java.sql.Date.class, Timestamp.class), DateConversion::toTimestamp); + DEFAULT_FACTORY.put(pair(Date.class, Timestamp.class), DateConversion::toTimestamp); + DEFAULT_FACTORY.put(pair(LocalDate.class, Timestamp.class), LocalDateConversion::toTimestamp); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, Timestamp.class), LocalDateTimeConversion::toTimestamp); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, Timestamp.class), ZonedDateTimeConversion::toTimestamp); + DEFAULT_FACTORY.put(pair(Calendar.class, Timestamp.class), CalendarConversion::toTimestamp); DEFAULT_FACTORY.put(pair(Number.class, Timestamp.class), NumberConversion::toTimestamp); DEFAULT_FACTORY.put(pair(Map.class, Timestamp.class), (fromInstance, converter, options) -> { Map map = (Map) fromInstance; @@ -512,13 +511,13 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(BigInteger.class, Calendar.class), NumberConversion::toCalendar); DEFAULT_FACTORY.put(pair(BigDecimal.class, Calendar.class), NumberConversion::toCalendar); DEFAULT_FACTORY.put(pair(AtomicLong.class, Calendar.class), NumberConversion::toCalendar); - DEFAULT_FACTORY.put(pair(Date.class, Calendar.class), (fromInstance, converter, options) -> initCal(((Date) fromInstance).getTime())); - DEFAULT_FACTORY.put(pair(java.sql.Date.class, Calendar.class), (fromInstance, converter, options) -> initCal(((Date) fromInstance).getTime())); - DEFAULT_FACTORY.put(pair(Timestamp.class, Calendar.class), (fromInstance, converter, options) -> initCal(((Date) fromInstance).getTime())); - DEFAULT_FACTORY.put(pair(LocalDate.class, Calendar.class), (fromInstance, converter, options) -> initCal(localDateToMillis((LocalDate) fromInstance, options.getSourceZoneId()))); - DEFAULT_FACTORY.put(pair(LocalDateTime.class, Calendar.class), (fromInstance, converter, options) -> initCal(localDateTimeToMillis((LocalDateTime) fromInstance, options.getSourceZoneId()))); - DEFAULT_FACTORY.put(pair(ZonedDateTime.class, Calendar.class), (fromInstance, converter, options) -> initCal(zonedDateTimeToMillis((ZonedDateTime) fromInstance))); - DEFAULT_FACTORY.put(pair(Calendar.class, Calendar.class), (fromInstance, converter, options) -> ((Calendar) fromInstance).clone()); + DEFAULT_FACTORY.put(pair(Date.class, Calendar.class), DateConversion::toCalendar); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, Calendar.class), DateConversion::toCalendar); + DEFAULT_FACTORY.put(pair(Timestamp.class, Calendar.class), DateConversion::toCalendar); + DEFAULT_FACTORY.put(pair(LocalDate.class, Calendar.class), LocalDateConversion::toCalendar); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, Calendar.class), LocalDateTimeConversion::toCalendar); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, Calendar.class), ZonedDateTimeConversion::toCalendar); + DEFAULT_FACTORY.put(pair(Calendar.class, Calendar.class), CalendarConversion::clone); DEFAULT_FACTORY.put(pair(Number.class, Calendar.class), NumberConversion::toCalendar); DEFAULT_FACTORY.put(pair(Map.class, Calendar.class), (fromInstance, converter, options) -> { Map map = (Map) fromInstance; @@ -529,7 +528,7 @@ private static void buildFactoryConversions() { String zone = (String) zoneRaw; tz = TimeZone.getTimeZone(zone); } else { - tz = TimeZone.getTimeZone(options.getTargetZoneId()); + tz = TimeZone.getTimeZone(options.getZoneId()); } Calendar cal = Calendar.getInstance(); cal.setTimeZone(tz); @@ -546,7 +545,7 @@ private static void buildFactoryConversions() { if (date == null) { return null; } - return initCal(date.getTime()); + return CalendarConversion.create(date.getTime(), options); }); // LocalTime conversions supported @@ -575,22 +574,19 @@ private static void buildFactoryConversions() { // LocalDate conversions supported DEFAULT_FACTORY.put(pair(Void.class, LocalDate.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Short.class, LocalDate.class), NumberConversion::toLocalDate); - DEFAULT_FACTORY.put(pair(Integer.class, LocalDate.class), NumberConversion::toLocalDate); DEFAULT_FACTORY.put(pair(Long.class, LocalDate.class), NumberConversion::toLocalDate); - DEFAULT_FACTORY.put(pair(Float.class, LocalDate.class), NumberConversion::toLocalDate); DEFAULT_FACTORY.put(pair(Double.class, LocalDate.class), NumberConversion::toLocalDate); DEFAULT_FACTORY.put(pair(BigInteger.class, LocalDate.class), NumberConversion::toLocalDate); DEFAULT_FACTORY.put(pair(BigDecimal.class, LocalDate.class), NumberConversion::toLocalDate); - DEFAULT_FACTORY.put(pair(AtomicInteger.class, LocalDate.class), NumberConversion::toLocalDate); DEFAULT_FACTORY.put(pair(AtomicLong.class, LocalDate.class), NumberConversion::toLocalDate); - DEFAULT_FACTORY.put(pair(java.sql.Date.class, LocalDate.class), (fromInstance, converter, options) -> ((java.sql.Date) fromInstance).toLocalDate()); - DEFAULT_FACTORY.put(pair(Timestamp.class, LocalDate.class), (fromInstance, converter, options) -> ((Timestamp) fromInstance).toLocalDateTime().toLocalDate()); - DEFAULT_FACTORY.put(pair(Date.class, LocalDate.class), (fromInstance, converter, options) -> ((Date) fromInstance).toInstant().atZone(ZoneId.systemDefault()).toLocalDate()); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, LocalDate.class), DateConversion::toLocalDate); + DEFAULT_FACTORY.put(pair(Timestamp.class, LocalDate.class), DateConversion::toLocalDate); + DEFAULT_FACTORY.put(pair(Date.class, LocalDate.class), DateConversion::toLocalDate); + DEFAULT_FACTORY.put(pair(Instant.class, LocalDate.class), InstantConversion::toLocalDate); DEFAULT_FACTORY.put(pair(LocalDate.class, LocalDate.class), Converter::identity); DEFAULT_FACTORY.put(pair(LocalDateTime.class, LocalDate.class), (fromInstance, converter, options) -> ((LocalDateTime) fromInstance).toLocalDate()); - DEFAULT_FACTORY.put(pair(ZonedDateTime.class, LocalDate.class), (fromInstance, converter, options) -> ((ZonedDateTime) fromInstance).toLocalDate()); - DEFAULT_FACTORY.put(pair(Calendar.class, LocalDate.class), (fromInstance, converter, options) -> ((Calendar) fromInstance).toInstant().atZone(ZoneId.systemDefault()).toLocalDate()); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, LocalDate.class), ZonedDateTimeConversion::toLocalDate); + DEFAULT_FACTORY.put(pair(Calendar.class, LocalDate.class), CalendarConversion::toLocalDate); DEFAULT_FACTORY.put(pair(Number.class, LocalDate.class), NumberConversion::toLocalDate); DEFAULT_FACTORY.put(pair(Map.class, LocalDate.class), (fromInstance, converter, options) -> { Map map = (Map) fromInstance; @@ -609,7 +605,7 @@ private static void buildFactoryConversions() { if (date == null) { return null; } - return date.toInstant().atZone(options.getTargetZoneId()).toLocalDate(); + return date.toInstant().atZone(options.getZoneId()).toLocalDate(); }); // LocalDateTime conversions supported @@ -619,13 +615,14 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(BigInteger.class, LocalDateTime.class), NumberConversion::toLocalDateTime); DEFAULT_FACTORY.put(pair(BigDecimal.class, LocalDateTime.class), NumberConversion::toLocalDateTime); DEFAULT_FACTORY.put(pair(AtomicLong.class, LocalDateTime.class), NumberConversion::toLocalDateTime); - DEFAULT_FACTORY.put(pair(java.sql.Date.class, LocalDateTime.class), (fromInstance, converter, options) -> ((java.sql.Date) fromInstance).toLocalDate().atStartOfDay()); - DEFAULT_FACTORY.put(pair(Timestamp.class, LocalDateTime.class), (fromInstance, converter, options) -> ((Timestamp) fromInstance).toLocalDateTime()); - DEFAULT_FACTORY.put(pair(Date.class, LocalDateTime.class), (fromInstance, converter, options) -> ((Date) fromInstance).toInstant().atZone(options.getSourceZoneId()).toLocalDateTime()); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, LocalDateTime.class), DateConversion::toLocalDateTime); + DEFAULT_FACTORY.put(pair(Timestamp.class, LocalDateTime.class), DateConversion::toLocalDateTime); + DEFAULT_FACTORY.put(pair(Date.class, LocalDateTime.class), DateConversion::toLocalDateTime); + DEFAULT_FACTORY.put(pair(Instant.class, LocalDateTime.class), InstantConversion::toLocalDateTime); DEFAULT_FACTORY.put(pair(LocalDateTime.class, LocalDateTime.class), Converter::identity); - DEFAULT_FACTORY.put(pair(LocalDate.class, LocalDateTime.class), (fromInstance, converter, options) -> ((LocalDate) fromInstance).atStartOfDay()); - DEFAULT_FACTORY.put(pair(ZonedDateTime.class, LocalDateTime.class), (fromInstance, converter, options) -> ((ZonedDateTime) fromInstance).toLocalDateTime()); - DEFAULT_FACTORY.put(pair(Calendar.class, LocalDateTime.class), (fromInstance, converter, options) -> ((Calendar) fromInstance).toInstant().atZone(options.getSourceZoneId()).toLocalDateTime()); + DEFAULT_FACTORY.put(pair(LocalDate.class, LocalDateTime.class), LocalDateConversion::toLocalDateTime); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, LocalDateTime.class), ZonedDateTimeConversion::toLocalDateTime); + DEFAULT_FACTORY.put(pair(Calendar.class, LocalDateTime.class), CalendarConversion::toLocalDateTime); DEFAULT_FACTORY.put(pair(Number.class, LocalDateTime.class), NumberConversion::toLocalDateTime); DEFAULT_FACTORY.put(pair(Map.class, LocalDateTime.class), (fromInstance, converter, options) -> { Map map = (Map) fromInstance; @@ -637,7 +634,7 @@ private static void buildFactoryConversions() { if (date == null) { return null; } - return date.toInstant().atZone(options.getSourceZoneId()).toLocalDateTime(); + return date.toInstant().atZone(options.getZoneId()).toLocalDateTime(); }); // ZonedDateTime conversions supported @@ -647,13 +644,13 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(BigInteger.class, ZonedDateTime.class), NumberConversion::toZonedDateTime); DEFAULT_FACTORY.put(pair(BigDecimal.class, ZonedDateTime.class), NumberConversion::toZonedDateTime); DEFAULT_FACTORY.put(pair(AtomicLong.class, ZonedDateTime.class), NumberConversion::toZonedDateTime); - DEFAULT_FACTORY.put(pair(java.sql.Date.class, ZonedDateTime.class), (fromInstance, converter, options) -> ((java.sql.Date) fromInstance).toLocalDate().atStartOfDay(options.getSourceZoneId())); - DEFAULT_FACTORY.put(pair(Timestamp.class, ZonedDateTime.class), (fromInstance, converter, options) -> ((Timestamp) fromInstance).toInstant().atZone(options.getSourceZoneId())); - DEFAULT_FACTORY.put(pair(Date.class, ZonedDateTime.class), (fromInstance, converter, options) -> ((Date) fromInstance).toInstant().atZone(options.getSourceZoneId())); - DEFAULT_FACTORY.put(pair(LocalDate.class, ZonedDateTime.class), (fromInstance, converter, options) -> ((LocalDate) fromInstance).atStartOfDay(options.getSourceZoneId())); - DEFAULT_FACTORY.put(pair(LocalDateTime.class, ZonedDateTime.class), (fromInstance, converter, options) -> ((LocalDateTime) fromInstance).atZone(options.getSourceZoneId())); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, ZonedDateTime.class), DateConversion::toZonedDateTime); + DEFAULT_FACTORY.put(pair(Timestamp.class, ZonedDateTime.class), DateConversion::toZonedDateTime); + DEFAULT_FACTORY.put(pair(Date.class, ZonedDateTime.class), DateConversion::toZonedDateTime); + DEFAULT_FACTORY.put(pair(LocalDate.class, ZonedDateTime.class), LocalDateConversion::toZonedDateTime); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, ZonedDateTime.class), LocalDateTimeConversion::toZonedDateTime); DEFAULT_FACTORY.put(pair(ZonedDateTime.class, ZonedDateTime.class), Converter::identity); - DEFAULT_FACTORY.put(pair(Calendar.class, ZonedDateTime.class), (fromInstance, converter, options) -> ((Calendar) fromInstance).toInstant().atZone(options.getSourceZoneId())); + DEFAULT_FACTORY.put(pair(Calendar.class, ZonedDateTime.class), CalendarConversion::toZonedDateTime); DEFAULT_FACTORY.put(pair(Number.class, ZonedDateTime.class), NumberConversion::toZonedDateTime); DEFAULT_FACTORY.put(pair(Map.class, ZonedDateTime.class), (fromInstance, converter, options) -> { Map map = (Map) fromInstance; @@ -665,7 +662,7 @@ private static void buildFactoryConversions() { if (date == null) { return null; } - return date.toInstant().atZone(options.getSourceZoneId()); + return date.toInstant().atZone(options.getZoneId()); }); // UUID conversions supported @@ -773,6 +770,25 @@ private static void buildFactoryConversions() { // Instant conversions supported DEFAULT_FACTORY.put(pair(Void.class, Instant.class), VoidConversion::toNull); DEFAULT_FACTORY.put(pair(Instant.class, Instant.class), Converter::identity); + + DEFAULT_FACTORY.put(pair(Long.class, Instant.class), NumberConversion::toInstant); + DEFAULT_FACTORY.put(pair(Double.class, Instant.class), NumberConversion::toInstant); + DEFAULT_FACTORY.put(pair(BigInteger.class, Instant.class), NumberConversion::toInstant); + DEFAULT_FACTORY.put(pair(BigDecimal.class, Instant.class), NumberConversion::toInstant); + DEFAULT_FACTORY.put(pair(AtomicLong.class, Instant.class), NumberConversion::toInstant); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, Instant.class), DateConversion::toInstant); + DEFAULT_FACTORY.put(pair(Timestamp.class, Instant.class), DateConversion::toInstant); + DEFAULT_FACTORY.put(pair(Date.class, Instant.class), DateConversion::toInstant); + DEFAULT_FACTORY.put(pair(LocalDate.class, Instant.class), LocalDateConversion::toInstant); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, Instant.class), LocalDateTimeConversion::toInstant); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, Instant.class), ZonedDateTimeConversion::toInstant); + DEFAULT_FACTORY.put(pair(Calendar.class, Instant.class), CalendarConversion::toInstant); + DEFAULT_FACTORY.put(pair(Number.class, Instant.class), NumberConversion::toInstant); + + + + + DEFAULT_FACTORY.put(pair(String.class, Instant.class), (fromInstance, converter, options) -> { try { return Instant.parse((String) fromInstance); @@ -894,11 +910,6 @@ public Converter(ConverterOptions options) { this.factory = new ConcurrentHashMap<>(DEFAULT_FACTORY); } - public ConverterOptions getOptions() - { - return options; - } - /** * Turn the passed in value to the class indicated. This will allow, for * example, a String to be passed in and be converted to a Long. @@ -1099,13 +1110,6 @@ private String name(Object fromInstance) { return getShortName(fromInstance.getClass()) + " (" + fromInstance + ")"; } - static Calendar initCal(long epochMs) { - Calendar cal = Calendar.getInstance(); - cal.clear(); - cal.setTimeInMillis(epochMs); - return cal; - } - private static Map initMap(Object from, Converter converter, ConverterOptions options) { Map map = new HashMap<>(); map.put(VALUE, from); @@ -1205,15 +1209,19 @@ public Convert addConversion(Class source, Class target, Convert con return factory.put(pair(source, target), conversionFunction); } - public static long localDateToMillis(LocalDate localDate, ZoneId zoneId) { + public long localDateToMillis(LocalDate localDate, ZoneId zoneId) { return localDate.atStartOfDay(zoneId).toInstant().toEpochMilli(); } - public static long localDateTimeToMillis(LocalDateTime localDateTime, ZoneId zoneId) { + public long localDateToMillis(LocalDate localDate) { + return localDateToMillis(localDate, options.getZoneId()); + } + + public long localDateTimeToMillis(LocalDateTime localDateTime, ZoneId zoneId) { return localDateTime.atZone(zoneId).toInstant().toEpochMilli(); } - public static long zonedDateTimeToMillis(ZonedDateTime zonedDateTime) { + public long zonedDateTimeToMillis(ZonedDateTime zonedDateTime) { return zonedDateTime.toInstant().toEpochMilli(); } diff --git a/src/main/java/com/cedarsoftware/util/convert/ConverterOptions.java b/src/main/java/com/cedarsoftware/util/convert/ConverterOptions.java index fabee345..30008478 100644 --- a/src/main/java/com/cedarsoftware/util/convert/ConverterOptions.java +++ b/src/main/java/com/cedarsoftware/util/convert/ConverterOptions.java @@ -5,6 +5,7 @@ import java.time.ZoneId; import java.util.Locale; import java.util.TimeZone; +import java.util.concurrent.ConcurrentHashMap; /** * @author Kenny Partlow (kpartlow@gmail.com) @@ -25,35 +26,29 @@ */ public interface ConverterOptions { + + ConcurrentHashMap customOptions = new ConcurrentHashMap(); + /** * @return zoneId to use for source conversion when on is not provided on the source (Date, Instant, etc.) */ - default ZoneId getSourceZoneId() { return ZoneId.systemDefault(); } + //TODO: should we just throw an exception here if they don't override? + default ZoneId getSourceZoneIdForLocalDates() { return ZoneId.systemDefault(); } /** * @return zoneId expected on the target when finished (only for types that support ZoneId or TimeZone) */ - default ZoneId getTargetZoneId() { return ZoneId.systemDefault(); } - - /** - * @return Locale to use as source locale when converting between types that require a Locale - */ - default Locale getSourceLocale() { return Locale.getDefault(); } + default ZoneId getZoneId() { return ZoneId.systemDefault(); } /** * @return Locale to use as target when converting between types that require a Locale. */ - default Locale getTargetLocale() { return Locale.getDefault(); } - - /** - * @return Charset to use as source CharSet on types that require a Charset during conversion (if required). - */ - default Charset getSourceCharset() { return StandardCharsets.UTF_8; } + default Locale getLocale() { return Locale.getDefault(); } /** * @return Charset to use os target Charset on types that require a Charset during conversion (if required). */ - default Charset getTargetCharset() { return StandardCharsets.UTF_8; } + default Charset getCharset() { return StandardCharsets.UTF_8; } /** @@ -64,15 +59,10 @@ public interface ConverterOptions { /** * @return custom option */ - T getCustomOption(String name); - - /** - * @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()); } + default T getCustomOption(String name) { return (T)customOptions.get(name); } /** * @return TimeZone expected on the target when finished (only for types that support ZoneId or TimeZone) */ - default TimeZone getTargetTimeZone() { return TimeZone.getTimeZone(this.getTargetZoneId()); } + default TimeZone getTimeZone() { return TimeZone.getTimeZone(this.getZoneId()); } } diff --git a/src/main/java/com/cedarsoftware/util/convert/DateConversion.java b/src/main/java/com/cedarsoftware/util/convert/DateConversion.java index dcfc4d91..fb2ca26a 100644 --- a/src/main/java/com/cedarsoftware/util/convert/DateConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/DateConversion.java @@ -1,22 +1,71 @@ package com.cedarsoftware.util.convert; import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; +import java.util.Calendar; import java.util.Date; import java.util.concurrent.atomic.AtomicLong; public class DateConversion { + + static long toLong(Object fromInstance) { + return ((Date) fromInstance).getTime(); + } + + static Instant toInstant(Object fromInstance) { + return Instant.ofEpochMilli(toLong(fromInstance)); + } + + static ZonedDateTime toZonedDateTime(Object fromInstance, ConverterOptions options) { + return toInstant(fromInstance).atZone(options.getZoneId()); + } + + static long toLong(Object fromInstance, Converter converter, ConverterOptions options) { + return toLong(fromInstance); + } + static Date toSqlDate(Object fromInstance, Converter converter, ConverterOptions options) { - Date from = (Date)fromInstance; - return new java.sql.Date(from.getTime()); + return new java.sql.Date(toLong(fromInstance)); + } + + static Timestamp toTimestamp(Object fromInstance, Converter converter, ConverterOptions options) { + return new Timestamp(toLong(fromInstance)); + } + + static Calendar toCalendar(Object fromInstance, Converter converter, ConverterOptions options) { + return CalendarConversion.create(toLong(fromInstance), options); } static BigDecimal toBigDecimal(Object fromInstance, Converter converter, ConverterOptions options) { - Date from = (Date)fromInstance; - return BigDecimal.valueOf(from.getTime()); + return BigDecimal.valueOf(toLong(fromInstance)); + } + + static Instant toInstant(Object fromInstance, Converter converter, ConverterOptions options) { + return toInstant(fromInstance); + } + + static ZonedDateTime toZonedDateTime(Object fromInstance, Converter converter, ConverterOptions options) { + return toZonedDateTime(fromInstance, options); + } + + static LocalDateTime toLocalDateTime(Object fromInstance, Converter converter, ConverterOptions options) { + return toZonedDateTime(fromInstance, options).toLocalDateTime(); + } + + static LocalDate toLocalDate(Object fromInstance, Converter converter, ConverterOptions options) { + return toZonedDateTime(fromInstance, options).toLocalDate(); + } + + static BigInteger toBigInteger(Object fromInstance, Converter converter, ConverterOptions options) { + return BigInteger.valueOf(toLong(fromInstance)); } static AtomicLong toAtomicLong(Object fromInstance, Converter converter, ConverterOptions options) { - Date from = (Date)fromInstance; - return new AtomicLong(from.getTime()); + return new AtomicLong(toLong(fromInstance)); } } diff --git a/src/main/java/com/cedarsoftware/util/convert/InstantConversion.java b/src/main/java/com/cedarsoftware/util/convert/InstantConversion.java new file mode 100644 index 00000000..e8704d9b --- /dev/null +++ b/src/main/java/com/cedarsoftware/util/convert/InstantConversion.java @@ -0,0 +1,67 @@ +package com.cedarsoftware.util.convert; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Calendar; +import java.util.Date; +import java.util.concurrent.atomic.AtomicLong; + +public class InstantConversion { + static long toLong(Object fromInstance, Converter converter, ConverterOptions options) { + Instant from = (Instant)fromInstance; + return from.toEpochMilli(); + } + + static float toFloat(Object fromInstance, Converter converter, ConverterOptions options) { + return toLong(fromInstance, converter, options); + } + + static double toDouble(Object fromInstance, Converter converter, ConverterOptions options) { + return toLong(fromInstance, converter, options); + } + + static AtomicLong toAtomicLong(Object fromInstance, Converter converter, ConverterOptions options) { + return new AtomicLong(toLong(fromInstance, converter, options)); + } + + static Timestamp toTimestamp(Object fromInstance, Converter converter, ConverterOptions options) { + return new Timestamp(toLong(fromInstance, converter, options)); + } + + static Calendar toCalendar(Object fromInstance, Converter converter, ConverterOptions options) { + long localDateMillis = toLong(fromInstance, converter, options); + return CalendarConversion.create(localDateMillis, options); + } + + static java.sql.Date toSqlDate(Object fromInstance, Converter converter, ConverterOptions options) { + return new java.sql.Date(toLong(fromInstance, converter, options)); + } + + static Date toDate(Object fromInstance, Converter converter, ConverterOptions options) { + return new Date(toLong(fromInstance, converter, options)); + } + + static BigInteger toBigInteger(Object fromInstance, Converter converter, ConverterOptions options) { + return BigInteger.valueOf(toLong(fromInstance, converter, options)); + } + + static BigDecimal toBigDecimal(Object fromInstance, Converter converter, ConverterOptions options) { + return BigDecimal.valueOf(toLong(fromInstance, converter, options)); + } + + static LocalDateTime toLocalDateTime(Object fromInstance, Converter converter, ConverterOptions options) { + Instant from = (Instant)fromInstance; + return from.atZone(options.getZoneId()).toLocalDateTime(); + } + + static LocalDate toLocalDate(Object fromInstance, Converter converter, ConverterOptions options) { + Instant from = (Instant)fromInstance; + return from.atZone(options.getZoneId()).toLocalDate(); + } + + +} diff --git a/src/main/java/com/cedarsoftware/util/convert/LocalDateConversion.java b/src/main/java/com/cedarsoftware/util/convert/LocalDateConversion.java new file mode 100644 index 00000000..0a5ef087 --- /dev/null +++ b/src/main/java/com/cedarsoftware/util/convert/LocalDateConversion.java @@ -0,0 +1,81 @@ +package com.cedarsoftware.util.convert; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; +import java.util.Calendar; +import java.util.Date; +import java.util.concurrent.atomic.AtomicLong; + +public class LocalDateConversion { + + private static ZonedDateTime toZonedDateTime(Object fromInstance, ConverterOptions options) { + return ((LocalDate)fromInstance).atStartOfDay(options.getZoneId()); + } + + static Instant toInstant(Object fromInstance, ConverterOptions options) { + return toZonedDateTime(fromInstance, options).toInstant(); + } + + static long toLong(Object fromInstance, ConverterOptions options) { + return toInstant(fromInstance, options).toEpochMilli(); + } + + static LocalDateTime toLocalDateTime(Object fromInstance, Converter converter, ConverterOptions options) { + return toZonedDateTime(fromInstance, options).toLocalDateTime(); + } + + static ZonedDateTime toZonedDateTime(Object fromInstance, Converter converter, ConverterOptions options) { + return toZonedDateTime(fromInstance, options).withZoneSameInstant(options.getZoneId()); + } + + static Instant toInstant(Object fromInstance, Converter converter, ConverterOptions options) { + return toZonedDateTime(fromInstance, options).toInstant(); + } + + + static long toLong(Object fromInstance, Converter converter, ConverterOptions options) { + return toInstant(fromInstance, options).toEpochMilli(); + } + + static float toFloat(Object fromInstance, Converter converter, ConverterOptions options) { + return toLong(fromInstance, converter, options); + } + + static double toDouble(Object fromInstance, Converter converter, ConverterOptions options) { + return toLong(fromInstance, converter, options); + } + + static AtomicLong toAtomicLong(Object fromInstance, Converter converter, ConverterOptions options) { + LocalDate from = (LocalDate)fromInstance; + return new AtomicLong(toLong(from, options)); + } + + static Timestamp toTimestamp(Object fromInstance, Converter converter, ConverterOptions options) { + return new Timestamp(toLong(fromInstance, options)); + } + + static Calendar toCalendar(Object fromInstance, Converter converter, ConverterOptions options) { + return CalendarConversion.create(toLong(fromInstance, options), options); + } + + static java.sql.Date toSqlDate(Object fromInstance, Converter converter, ConverterOptions options) { + return new java.sql.Date(toLong(fromInstance, options)); + } + + static Date toDate(Object fromInstance, Converter converter, ConverterOptions options) { + return new Date(toLong(fromInstance, options)); + } + + static BigInteger toBigInteger(Object fromInstance, Converter converter, ConverterOptions options) { + return BigInteger.valueOf(toLong(fromInstance, options)); + } + + static BigDecimal toBigDecimal(Object fromInstance, Converter converter, ConverterOptions options) { + return BigDecimal.valueOf(toLong(fromInstance, options)); + } +} diff --git a/src/main/java/com/cedarsoftware/util/convert/LocalDateTimeConversion.java b/src/main/java/com/cedarsoftware/util/convert/LocalDateTimeConversion.java new file mode 100644 index 00000000..0a433b21 --- /dev/null +++ b/src/main/java/com/cedarsoftware/util/convert/LocalDateTimeConversion.java @@ -0,0 +1,70 @@ +package com.cedarsoftware.util.convert; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.concurrent.atomic.AtomicLong; + +public class LocalDateTimeConversion { + private static ZonedDateTime toZonedDateTime(Object fromInstance, ConverterOptions options) { + return ((LocalDateTime)fromInstance).atZone(options.getSourceZoneIdForLocalDates()); + } + + private static Instant toInstant(Object fromInstance, ConverterOptions options) { + return toZonedDateTime(fromInstance, options).toInstant(); + } + + private static long toLong(Object fromInstance, ConverterOptions options) { + return toInstant(fromInstance, options).toEpochMilli(); + } + + static ZonedDateTime toZonedDateTime(Object fromInstance, Converter converter, ConverterOptions options) { + return toZonedDateTime(fromInstance, options).withZoneSameInstant(options.getZoneId()); + } + + static Instant toInstant(Object fromInstance, Converter converter, ConverterOptions options) { + return toInstant(fromInstance, options); + } + + static long toLong(Object fromInstance, Converter converter, ConverterOptions options) { + return toLong(fromInstance, options); + } + + static AtomicLong toAtomicLong(Object fromInstance, Converter converter, ConverterOptions options) { + return new AtomicLong(toLong(fromInstance, options)); + } + + static Timestamp toTimestamp(Object fromInstance, Converter converter, ConverterOptions options) { + return new Timestamp(toLong(fromInstance, options)); + } + + static Calendar toCalendar(Object fromInstance, Converter converter, ConverterOptions options) { + ZonedDateTime time = toZonedDateTime(fromInstance, options); + GregorianCalendar calendar = new GregorianCalendar(options.getTimeZone()); + calendar.setTimeInMillis(time.toInstant().toEpochMilli()); + return calendar; + } + + static java.sql.Date toSqlDate(Object fromInstance, Converter converter, ConverterOptions options) { + return new java.sql.Date(toLong(fromInstance, options)); + } + + static Date toDate(Object fromInstance, Converter converter, ConverterOptions options) { + return new Date(toLong(fromInstance, options)); + } + + static BigInteger toBigInteger(Object fromInstance, Converter converter, ConverterOptions options) { + return BigInteger.valueOf(toLong(fromInstance, options)); + } + + static BigDecimal toBigDecimal(Object fromInstance, Converter converter, ConverterOptions options) { + return BigDecimal.valueOf(toLong(fromInstance, options)); + } +} diff --git a/src/main/java/com/cedarsoftware/util/convert/MapConversion.java b/src/main/java/com/cedarsoftware/util/convert/MapConversion.java index 8a0a0637..1c688c95 100644 --- a/src/main/java/com/cedarsoftware/util/convert/MapConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/MapConversion.java @@ -1,12 +1,17 @@ package com.cedarsoftware.util.convert; +import com.cedarsoftware.util.Convention; + import java.math.BigDecimal; import java.math.BigInteger; +import java.util.Arrays; import java.util.Map; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Supplier; public class MapConversion { @@ -27,72 +32,115 @@ static Object toUUID(Object fromInstance, Converter converter, ConverterOptions } static Byte toByte(Object fromInstance, Converter converter, ConverterOptions options) { - return fromMapValue(fromInstance, converter, options, Byte.class); + return fromValue(fromInstance, converter, options, Byte.class); } static Short toShort(Object fromInstance, Converter converter, ConverterOptions options) { - return fromMapValue(fromInstance, converter, options, Short.class); + return fromValue(fromInstance, converter, options, Short.class); } static Integer toInt(Object fromInstance, Converter converter, ConverterOptions options) { - return fromMapValue(fromInstance, converter, options, Integer.class); + return fromValue(fromInstance, converter, options, Integer.class); } static Long toLong(Object fromInstance, Converter converter, ConverterOptions options) { - return fromMapValue(fromInstance, converter, options, Long.class); + return fromValue(fromInstance, converter, options, Long.class); } static Float toFloat(Object fromInstance, Converter converter, ConverterOptions options) { - return fromMapValue(fromInstance, converter, options, Float.class); + return fromValue(fromInstance, converter, options, Float.class); } static Double toDouble(Object fromInstance, Converter converter, ConverterOptions options) { - return fromMapValue(fromInstance, converter, options, Double.class); + return fromValue(fromInstance, converter, options, Double.class); } static Boolean toBoolean(Object fromInstance, Converter converter, ConverterOptions options) { - return fromMapValue(fromInstance, converter, options, Boolean.class); + return fromValue(fromInstance, converter, options, Boolean.class); } static BigDecimal toBigDecimal(Object fromInstance, Converter converter, ConverterOptions options) { - return fromMapValue(fromInstance, converter, options, BigDecimal.class); + return fromValue(fromInstance, converter, options, BigDecimal.class); } static BigInteger toBigInteger(Object fromInstance, Converter converter, ConverterOptions options) { - return fromMapValue(fromInstance, converter, options, BigInteger.class); + return fromValue(fromInstance, converter, options, BigInteger.class); } static String toString(Object fromInstance, Converter converter, ConverterOptions options) { - return fromMapValue(fromInstance, converter, options, String.class); + return fromValue(fromInstance, converter, options, String.class); } - static AtomicInteger toAtomicInteger(Object fromInstance, Converter converter, ConverterOptions options) { - return fromMapValue(fromInstance, converter, options, AtomicInteger.class); + return fromValue(fromInstance, converter, options, AtomicInteger.class); } static AtomicLong toAtomicLong(Object fromInstance, Converter converter, ConverterOptions options) { - return fromMapValue(fromInstance, converter, options, AtomicLong.class); + return fromValue(fromInstance, converter, options, AtomicLong.class); } static AtomicBoolean toAtomicBoolean(Object fromInstance, Converter converter, ConverterOptions options) { - return fromMapValue(fromInstance, converter, options, AtomicBoolean.class); + return fromValue(fromInstance, converter, options, AtomicBoolean.class); + } + + private static final String TIME = "time"; + + static java.sql.Date toSqlDate(Object fromInstance, Converter converter, ConverterOptions options) { + return fromKeyOrValue(fromInstance, TIME, java.sql.Date.class, converter, options); + } + + /** + * Allows you to check for a single named key and convert that to a type of it exists, otherwise falls back + * onto the value type V or VALUE. + * @return type if it exists, else returns what is in V or VALUE + * @param type of object to convert the value. + */ + static T fromKeyOrValue(final Object fromInstance, final String key, final Class type, final Converter converter, final ConverterOptions options) { + Convention.throwIfFalse(fromInstance instanceof Map, "fromInstance must be an instance of map"); + Convention.throwIfNullOrEmpty(key, "key cannot be null or empty"); + Convention.throwIfNull(type, "type cannot be null"); + Convention.throwIfNull(converter, "converter cannot be null"); + Convention.throwIfNull(options, "options cannot be null"); + + Map map = (Map) fromInstance; + + if (map.containsKey(key)) { + return converter.convert(key, type, options); + } + + if (map.containsKey(V)) { + return converter.convert(map.get(V), type, options); + } + + if (map.containsKey(VALUE)) { + return converter.convert(map.get(VALUE), type, options); + } + + throw new IllegalArgumentException(String.format("To convert from Map to %s the map must include keys: %s, '_v' or 'value' an associated value to convert from.", getShortName(type), key)); } - static T fromMapValue(Object fromInstance, Converter converter, ConverterOptions options, Class type) { + static T fromValue(Object fromInstance, Converter converter, ConverterOptions options, Class type) { + Convention.throwIfFalse(fromInstance instanceof Map, "fromInstance must be an instance of map"); + Convention.throwIfNull(type, "type cannot be null"); + Convention.throwIfNull(converter, "converter cannot be null"); + Convention.throwIfNull(options, "options cannot be null"); + Map map = (Map) fromInstance; if (map.containsKey(V)) { - return converter.convert(map.get(V), type); + return converter.convert(map.get(V), type, options); } if (map.containsKey(VALUE)) { - return converter.convert(map.get(VALUE), type); + return converter.convert(map.get(VALUE), type, options); } - throw new IllegalArgumentException("To convert from Map to " + getShortName(type) + ", the map must include keys: '_v' or 'value' an associated value to convert from."); + throw new IllegalArgumentException(String.format("To convert from Map to %s the map must include keys: '_v' or 'value' an associated value to convert from.", getShortName(type))); } + static Optional convert(Map map, String key, Class type, Converter converter, ConverterOptions options) { + return map.containsKey(key) ? Optional.of(converter.convert(map.get(key), type, options)) : Optional.empty(); + } private static T getConvertedValue(Map map, String key, Class type, Converter converter, ConverterOptions options) { // NOPE STUFF? diff --git a/src/main/java/com/cedarsoftware/util/convert/NumberConversion.java b/src/main/java/com/cedarsoftware/util/convert/NumberConversion.java index f31e85e4..1c968e79 100644 --- a/src/main/java/com/cedarsoftware/util/convert/NumberConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/NumberConversion.java @@ -33,7 +33,7 @@ public class NumberConversion { static byte toByte(Object from, Converter converter, ConverterOptions options) { - return ((Number) from).byteValue(); + return ((Number)from).byteValue(); } static Byte toByteZero(Object from, Converter converter, ConverterOptions options) { @@ -42,7 +42,7 @@ static Byte toByteZero(Object from, Converter converter, ConverterOptions option static short toShort(Object from, Converter converter, ConverterOptions options) { - return ((Number) from).shortValue(); + return ((Number)from).shortValue(); } static Short toShortZero(Object from, Converter converter, ConverterOptions options) { @@ -50,7 +50,7 @@ static Short toShortZero(Object from, Converter converter, ConverterOptions opti } static int toInt(Object from, Converter converter, ConverterOptions options) { - return ((Number) from).intValue(); + return ((Number)from).intValue(); } static Integer toIntZero(Object from, Converter converter, ConverterOptions options) { @@ -59,9 +59,17 @@ static Integer toIntZero(Object from, Converter converter, ConverterOptions opti static long toLong(Object from, Converter converter, ConverterOptions options) { + return toLong(from); + } + + static long toLong(Object from) { return ((Number) from).longValue(); } + static int toInt(Object from) { + return ((Number)from).intValue(); + } + static Long toLongZero(Object from, Converter converter, ConverterOptions options) { return CommonValues.LONG_ZERO; } @@ -77,67 +85,74 @@ static Float toFloatZero(Object from, Converter converter, ConverterOptions opti static double toDouble(Object from, Converter converter, ConverterOptions options) { + return toDouble(from); + } + + static double toDouble(Object from) { return ((Number) from).doubleValue(); } + static Double toDoubleZero(Object from, Converter converter, ConverterOptions options) { return CommonValues.DOUBLE_ZERO; } static BigDecimal integerTypeToBigDecimal(Object from, Converter converter, ConverterOptions options) { - return BigDecimal.valueOf(((Number) from).longValue()); + return BigDecimal.valueOf(toLong(from)); + } + + static BigInteger integerTypeToBigInteger(Object from, Converter converter, ConverterOptions options) { + return BigInteger.valueOf(toLong(from)); } static AtomicLong toAtomicLong(Object from, Converter converter, ConverterOptions options) { - Number n = (Number)from; - return new AtomicLong(n.longValue()); + return new AtomicLong(toLong(from)); } static AtomicInteger toAtomicInteger(Object from, Converter converter, ConverterOptions options) { - Number n = (Number)from; - return new AtomicInteger(n.intValue()); + return new AtomicInteger(toInt(from)); } static BigDecimal bigIntegerToBigDecimal(Object from, Converter converter, ConverterOptions options) { return new BigDecimal((BigInteger)from); } + static BigInteger bigDecimalToBigInteger(Object from, Converter converter, ConverterOptions options) { + return ((BigDecimal)from).toBigInteger(); + } + static AtomicBoolean toAtomicBoolean(Object from, Converter converter, ConverterOptions options) { - Number number = (Number) from; - return new AtomicBoolean(number.longValue() != 0); + return new AtomicBoolean(toLong(from) != 0); } static BigDecimal floatingPointToBigDecimal(Object from, Converter converter, ConverterOptions options) { - Number n = (Number)from; - return BigDecimal.valueOf(n.doubleValue()); + return BigDecimal.valueOf(toDouble(from)); } static boolean isIntTypeNotZero(Object from, Converter converter, ConverterOptions options) { - return ((Number) from).longValue() != 0; + return toLong(from) != 0; } static boolean isFloatTypeNotZero(Object from, Converter converter, ConverterOptions options) { - return ((Number) from).doubleValue() != 0; + return toDouble(from) != 0; } static boolean isBigIntegerNotZero(Object from, Converter converter, ConverterOptions options) { - BigInteger bi = (BigInteger) from; - return bi.compareTo(BigInteger.ZERO) != 0; + return ((BigInteger)from).compareTo(BigInteger.ZERO) != 0; } static boolean isBigDecimalNotZero(Object from, Converter converter, ConverterOptions options) { - BigDecimal bd = (BigDecimal) from; - return bd.compareTo(BigDecimal.ZERO) != 0; + return ((BigDecimal)from).compareTo(BigDecimal.ZERO) != 0; } /** - * @param number Number instance to convert to char. + * @param from Number instance to convert to char. * @return char that best represents the Number. The result will always be a value between * 0 and Character.MAX_VALUE. * @throws IllegalArgumentException if the value exceeds the range of a char. */ - static char toCharacter(Number number) { - long value = number.longValue(); + static char toCharacter(Object from) { + long value = toLong(from); if (value >= 0 && value <= Character.MAX_VALUE) { return (char) value; } @@ -153,41 +168,38 @@ static char toCharacter(Number number) { * @throws IllegalArgumentException if the value exceeds the range of a char. */ static char toCharacter(Object from, Converter converter, ConverterOptions options) { - return toCharacter((Number) from); + return toCharacter(from); } static Date toDate(Object from, Converter converter, ConverterOptions options) { - Number number = (Number) from; - return new Date(number.longValue()); + return new Date(toLong(from)); + } + + static Instant toInstant(Object from, Converter converter, ConverterOptions options) { + return Instant.ofEpochMilli(toLong(from)); } static java.sql.Date toSqlDate(Object from, Converter converter, ConverterOptions options) { - Number number = (Number) from; - return new java.sql.Date(number.longValue()); + return new java.sql.Date(toLong(from)); } static Timestamp toTimestamp(Object from, Converter converter, ConverterOptions options) { - Number number = (Number) from; - return new Timestamp(number.longValue()); + return new Timestamp(toLong(from)); } static Calendar toCalendar(Object from, Converter converter, ConverterOptions options) { - Number number = (Number) from; - return Converter.initCal(number.longValue()); + return CalendarConversion.create(toLong(from), options); } static LocalDate toLocalDate(Object from, Converter converter, ConverterOptions options) { - Number number = (Number) from; - return LocalDate.ofEpochDay(number.longValue()); + return Instant.ofEpochMilli(toLong(from)).atZone(options.getZoneId()).toLocalDate(); } static LocalDateTime toLocalDateTime(Object from, Converter converter, ConverterOptions options) { - Number number = (Number) from; - return Instant.ofEpochMilli(number.longValue()).atZone(options.getSourceZoneId()).toLocalDateTime(); + return Instant.ofEpochMilli(toLong(from)).atZone(options.getZoneId()).toLocalDateTime(); } static ZonedDateTime toZonedDateTime(Object from, Converter converter, ConverterOptions options) { - Number number = (Number) from; - return Instant.ofEpochMilli(number.longValue()).atZone(options.getSourceZoneId()); + return Instant.ofEpochMilli(toLong(from)).atZone(options.getZoneId()); } } diff --git a/src/main/java/com/cedarsoftware/util/convert/StringConversion.java b/src/main/java/com/cedarsoftware/util/convert/StringConversion.java index 6da35e6f..eb349f7e 100644 --- a/src/main/java/com/cedarsoftware/util/convert/StringConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/StringConversion.java @@ -4,10 +4,14 @@ import java.math.BigInteger; import java.math.RoundingMode; import java.util.Date; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import com.cedarsoftware.util.CaseInsensitiveSet; +import com.cedarsoftware.util.CollectionUtilities; import com.cedarsoftware.util.DateUtilities; /** @@ -206,7 +210,7 @@ static Boolean toBoolean(Object from, Converter converter, ConverterOptions opti } else if ("false".equals(str)) { return false; } - return "true".equalsIgnoreCase(str) || "t".equalsIgnoreCase(str); + return "true".equalsIgnoreCase(str) || "t".equalsIgnoreCase(str) || "1".equalsIgnoreCase(str); } static char toCharacter(Object from, Converter converter, ConverterOptions options) { diff --git a/src/main/java/com/cedarsoftware/util/convert/ZonedDateTimeConversion.java b/src/main/java/com/cedarsoftware/util/convert/ZonedDateTimeConversion.java new file mode 100644 index 00000000..1a765188 --- /dev/null +++ b/src/main/java/com/cedarsoftware/util/convert/ZonedDateTimeConversion.java @@ -0,0 +1,76 @@ +package com.cedarsoftware.util.convert; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZonedDateTime; +import java.util.Calendar; +import java.util.Date; +import java.util.concurrent.atomic.AtomicLong; + +public class ZonedDateTimeConversion { + + static ZonedDateTime toDifferentZone(Object fromInstance, ConverterOptions options) { + return ((ZonedDateTime)fromInstance).withZoneSameInstant(options.getZoneId()); + } + + static Instant toInstant(Object fromInstance) { + return ((ZonedDateTime)fromInstance).toInstant(); + } + + static long toLong(Object fromInstance) { + return toInstant(fromInstance).toEpochMilli(); + } + + static long toLong(Object fromInstance, Converter converter, ConverterOptions options) { + return toLong(fromInstance); + } + + static Instant toInstant(Object fromInstance, Converter converter, ConverterOptions options) { + return toInstant(fromInstance); + } + + static LocalDateTime toLocalDateTime(Object fromInstance, Converter converter, ConverterOptions options) { + return toDifferentZone(fromInstance, options).toLocalDateTime(); + } + + static LocalDate toLocalDate(Object fromInstance, Converter converter, ConverterOptions options) { + return toDifferentZone(fromInstance, options).toLocalDate(); + } + + static LocalTime toLocalTime(Object fromInstance, Converter converter, ConverterOptions options) { + return toDifferentZone(fromInstance, options).toLocalTime(); + } + + static AtomicLong toAtomicLong(Object fromInstance, Converter converter, ConverterOptions options) { + return new AtomicLong(toLong(fromInstance)); + } + + static Timestamp toTimestamp(Object fromInstance, Converter converter, ConverterOptions options) { + return new Timestamp(toLong(fromInstance)); + } + + static Calendar toCalendar(Object fromInstance, Converter converter, ConverterOptions options) { + return CalendarConversion.create(toLong(fromInstance), options); + } + + static java.sql.Date toSqlDate(Object fromInstance, Converter converter, ConverterOptions options) { + return new java.sql.Date(toLong(fromInstance)); + } + + static Date toDate(Object fromInstance, Converter converter, ConverterOptions options) { + return new Date(toLong(fromInstance)); + } + + static BigInteger toBigInteger(Object fromInstance, Converter converter, ConverterOptions options) { + return BigInteger.valueOf(toLong(fromInstance)); + } + + static BigDecimal toBigDecimal(Object fromInstance, Converter converter, ConverterOptions options) { + return BigDecimal.valueOf(toLong(fromInstance)); + } +} diff --git a/src/test/java/com/cedarsoftware/util/convert/ConverterTest.java b/src/test/java/com/cedarsoftware/util/convert/ConverterTest.java index 8cc10d93..d7767f0f 100644 --- a/src/test/java/com/cedarsoftware/util/convert/ConverterTest.java +++ b/src/test/java/com/cedarsoftware/util/convert/ConverterTest.java @@ -32,9 +32,9 @@ import org.junit.jupiter.params.provider.NullAndEmptySource; import org.junit.jupiter.params.provider.NullSource; -import static com.cedarsoftware.util.convert.Converter.localDateTimeToMillis; -import static com.cedarsoftware.util.convert.Converter.localDateToMillis; -import static com.cedarsoftware.util.convert.Converter.zonedDateTimeToMillis; +import static com.cedarsoftware.util.Converter.localDateTimeToMillis; +import static com.cedarsoftware.util.Converter.localDateToMillis; +import static com.cedarsoftware.util.Converter.zonedDateTimeToMillis; import static com.cedarsoftware.util.convert.ConverterTest.fubar.bar; import static com.cedarsoftware.util.convert.ConverterTest.fubar.foo; import static org.assertj.core.api.Assertions.assertThat; @@ -47,7 +47,7 @@ import static org.junit.jupiter.api.Assertions.fail; /** - * @author John DeRegnaucourt (jdereg@gmail.com) & Ken Partlow + * @aFuthor John DeRegnaucourt (jdereg@gmail.com) & Ken Partlow *
* Copyright (c) Cedar Software LLC *

@@ -79,7 +79,7 @@ public void before() { this.converter = new Converter(new DefaultConverterOptions()); } - private static Stream testByte_minValue_params() { + private static Stream toByte_minValueParams() { return Stream.of( Arguments.of("-128"), Arguments.of(Byte.MIN_VALUE), @@ -96,23 +96,23 @@ private static Stream testByte_minValue_params() { } @ParameterizedTest - @MethodSource("testByte_minValue_params") - void testByte_minValue(Object value) + @MethodSource("toByte_minValueParams") + void toByte_convertsToByteMinValue(Object value) { Byte converted = this.converter.convert(value, Byte.class); assertThat(converted).isEqualTo(Byte.MIN_VALUE); } @ParameterizedTest - @MethodSource("testByte_minValue_params") - void testByte_minValue_usingPrimitive(Object value) + @MethodSource("toByte_minValueParams") + void toByteAsPrimitive_convertsToByteMinValue(Object value) { byte converted = this.converter.convert(value, byte.class); assertThat(converted).isEqualTo(Byte.MIN_VALUE); } - private static Stream testByte_maxValue_params() { + private static Stream toByte_maxValueParams() { return Stream.of( Arguments.of("127.9"), Arguments.of("127"), @@ -129,22 +129,22 @@ private static Stream testByte_maxValue_params() { } @ParameterizedTest - @MethodSource("testByte_maxValue_params") - void testByte_maxValue(Object value) + @MethodSource("toByte_maxValueParams") + void toByte_returnsByteMaxValue(Object value) { Byte converted = this.converter.convert(value, Byte.class); assertThat(converted).isEqualTo(Byte.MAX_VALUE); } @ParameterizedTest - @MethodSource("testByte_maxValue_params") - void testByte_maxValue_usingPrimitive(Object value) + @MethodSource("toByte_maxValueParams") + void toByte_withPrimitiveType_returnsByteMaxVAlue(Object value) { byte converted = this.converter.convert(value, byte.class); assertThat(converted).isEqualTo(Byte.MAX_VALUE); } - private static Stream testByte_booleanParams() { + private static Stream toByte_booleanParams() { return Stream.of( Arguments.of( true, CommonValues.BYTE_ONE), Arguments.of( false, CommonValues.BYTE_ZERO), @@ -155,22 +155,22 @@ private static Stream testByte_booleanParams() { } @ParameterizedTest - @MethodSource("testByte_booleanParams") - void testByte_fromBoolean(Object value, Byte expectedResult) + @MethodSource("toByte_booleanParams") + void toByte_fromBoolean_isSameAsCommonValueObject(Object value, Byte expectedResult) { Byte converted = this.converter.convert(value, Byte.class); assertThat(converted).isSameAs(expectedResult); } @ParameterizedTest - @MethodSource("testByte_booleanParams") - void testByte_fromBoolean_usingPrimitive(Object value, Byte expectedResult) + @MethodSource("toByte_booleanParams") + void toByte_fromBoolean_usingPrimitive_isSameAsCommonValueObject(Object value, Byte expectedResult) { byte converted = this.converter.convert(value, byte.class); assertThat(converted).isSameAs(expectedResult); } - private static Stream testByteParams_withIllegalArguments() { + private static Stream toByte_illegalArguments() { return Stream.of( Arguments.of("45badNumber", "not parseable as a byte"), Arguments.of("-129", "not parseable as a byte"), @@ -179,8 +179,8 @@ private static Stream testByteParams_withIllegalArguments() { } @ParameterizedTest - @MethodSource("testByteParams_withIllegalArguments") - void testByte_withIllegalArguments(Object value, String partialMessage) { + @MethodSource("toByte_illegalArguments") + void toByte_withIllegalArguments(Object value, String partialMessage) { assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy(() -> this.converter.convert(value, byte.class)) .withMessageContaining(partialMessage); @@ -188,7 +188,7 @@ void testByte_withIllegalArguments(Object value, String partialMessage) { @ParameterizedTest @NullAndEmptySource - void testConvertToPrimitiveByte_whenEmptyOrNullString(String s) + void toByte_whenNullOrEmpty_andCovnertingToPrimitive_returnsZero(String s) { byte converted = this.converter.convert(s, byte.class); assertThat(converted).isZero(); @@ -196,7 +196,7 @@ void testConvertToPrimitiveByte_whenEmptyOrNullString(String s) @ParameterizedTest @NullSource - void testConvertToByte_whenNullString(String s) + void toByte_whenNull_andNotPrimitive_returnsNull(String s) { Byte converted = this.converter.convert(s, Byte.class); assertThat(converted).isNull(); @@ -204,13 +204,13 @@ void testConvertToByte_whenNullString(String s) @ParameterizedTest @EmptySource - void testConvertToByte_whenEmptyString(String s) + void toByte_whenEmpty_andNotPrimitive_returnsZero(String s) { Byte converted = this.converter.convert(s, Byte.class); assertThat(converted).isZero(); } - private static Stream testShortParams() { + private static Stream toShortParams() { return Stream.of( Arguments.of("-32768.9", (short)-32768), Arguments.of("-32768", (short)-32768), @@ -237,21 +237,21 @@ private static Stream testShortParams() { @ParameterizedTest - @MethodSource("testShortParams") - void testShort(Object value, Short expectedResult) + @MethodSource("toShortParams") + void toShort(Object value, Short expectedResult) { Short converted = this.converter.convert(value, Short.class); assertThat(converted).isEqualTo(expectedResult); } @ParameterizedTest - @MethodSource("testShortParams") - void testShort_usingPrimitive(Object value, short expectedResult) { + @MethodSource("toShortParams") + void toShort_usingPrimitiveClass(Object value, short expectedResult) { short converted = this.converter.convert(value, short.class); assertThat(converted).isEqualTo(expectedResult); } - private static Stream testShort_booleanParams() { + private static Stream toShort_withBooleanPrams() { return Stream.of( Arguments.of( true, CommonValues.SHORT_ONE), Arguments.of( false, CommonValues.SHORT_ZERO), @@ -262,22 +262,22 @@ private static Stream testShort_booleanParams() { } @ParameterizedTest - @MethodSource("testShort_booleanParams") - void testShort_fromBoolean(Object value, Short expectedResult) + @MethodSource("toShort_withBooleanPrams") + void toShort_withBooleanPrams_returnsCommonValue(Object value, Short expectedResult) { Short converted = this.converter.convert(value, Short.class); assertThat(converted).isSameAs(expectedResult); } @ParameterizedTest - @MethodSource("testShort_booleanParams") - void testShort_fromBoolean_usingPrimitives(Object value, Short expectedResult) + @MethodSource("toShort_withBooleanPrams") + void toShort_withBooleanPrams_usingPrimitive_returnsCommonValue(Object value, Short expectedResult) { short converted = this.converter.convert(value, short.class); assertThat(converted).isSameAs(expectedResult); } - private static Stream testShortParams_withIllegalArguments() { + private static Stream toShortParams_withIllegalArguments() { return Stream.of( Arguments.of("45badNumber", "not parseable as a short value or outside -32768 to 32767"), Arguments.of("-32769", "not parseable as a short value or outside -32768 to 32767"), @@ -286,8 +286,8 @@ private static Stream testShortParams_withIllegalArguments() { } @ParameterizedTest - @MethodSource("testShortParams_withIllegalArguments") - void testShort_withIllegalArguments(Object value, String partialMessage) { + @MethodSource("toShortParams_withIllegalArguments") + void toShort_withIllegalArguments_throwsException(Object value, String partialMessage) { assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy(() -> this.converter.convert(value, short.class)) .withMessageContaining(partialMessage); @@ -295,7 +295,7 @@ void testShort_withIllegalArguments(Object value, String partialMessage) { @ParameterizedTest @NullAndEmptySource - void testConvertToPrimitiveShort_whenEmptyOrNullString(String s) + void toShort_usingPrimitive_withNullAndEmptySource_returnsZero(String s) { short converted = this.converter.convert(s, short.class); assertThat(converted).isZero(); @@ -303,7 +303,7 @@ void testConvertToPrimitiveShort_whenEmptyOrNullString(String s) @ParameterizedTest @NullSource - void testConvertToShort_whenNullString(String s) + void toShort_whenNotPrimitive_whenNull_returnsNull(String s) { Short converted = this.converter.convert(s, Short.class); assertThat(converted).isNull(); @@ -311,13 +311,13 @@ void testConvertToShort_whenNullString(String s) @ParameterizedTest @EmptySource - void testConvertToShort_whenEmptyString(String s) + void toShort_whenNotPrimitive_whenEmptyString_returnsNull(String s) { Short converted = this.converter.convert(s, Short.class); assertThat(converted).isZero(); } - private static Stream testIntParams() { + private static Stream toIntParams() { return Stream.of( Arguments.of("-32768", -32768), Arguments.of("-45000", -45000), @@ -346,23 +346,23 @@ private static Stream testIntParams() { } @ParameterizedTest - @MethodSource("testIntParams") - void testInt(Object value, Integer expectedResult) + @MethodSource("toIntParams") + void toInt(Object value, Integer expectedResult) { Integer converted = this.converter.convert(value, Integer.class); assertThat(converted).isEqualTo(expectedResult); } @ParameterizedTest - @MethodSource("testShortParams") - void testInt_usingPrimitive(Object value, int expectedResult) + @MethodSource("toIntParams") + void toInt_usingPrimitives(Object value, int expectedResult) { int converted = this.converter.convert(value, int.class); assertThat(converted).isEqualTo(expectedResult); } - private static Stream testInt_booleanParams() { + private static Stream toInt_booleanParams() { return Stream.of( Arguments.of( true, CommonValues.INTEGER_ONE), Arguments.of( false, CommonValues.INTEGER_ZERO), @@ -373,15 +373,15 @@ private static Stream testInt_booleanParams() { } @ParameterizedTest - @MethodSource("testInt_booleanParams") - void testInt_fromBoolean(Object value, Integer expectedResult) + @MethodSource("toInt_booleanParams") + void toInt_fromBoolean_returnsCommonValue(Object value, Integer expectedResult) { Integer converted = this.converter.convert(value, Integer.class); assertThat(converted).isSameAs(expectedResult); } - private static Stream testIntegerParams_withIllegalArguments() { + private static Stream toInt_illegalArguments() { return Stream.of( Arguments.of("45badNumber", "Value: 45badNumber not parseable as an int value or outside -2147483648 to 2147483647"), Arguments.of( "12147483648", "Value: 12147483648 not parseable as an int value or outside -2147483648 to 2147483647"), @@ -390,8 +390,8 @@ private static Stream testIntegerParams_withIllegalArguments() { } @ParameterizedTest - @MethodSource("testIntegerParams_withIllegalArguments") - void testInteger_withIllegalArguments(Object value, String partialMessage) { + @MethodSource("toInt_illegalArguments") + void toInt_withIllegalArguments_throwsException(Object value, String partialMessage) { assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy(() -> this.converter.convert(value, Integer.class)) .withMessageContaining(partialMessage); @@ -400,7 +400,7 @@ void testInteger_withIllegalArguments(Object value, String partialMessage) { @ParameterizedTest @NullAndEmptySource - void testConvertToPrimitiveInteger_whenEmptyOrNullString(String s) + void toInt_usingPrimitive_whenEmptyOrNullString_returnsZero(String s) { int converted = this.converter.convert(s, int.class); assertThat(converted).isZero(); @@ -408,7 +408,7 @@ void testConvertToPrimitiveInteger_whenEmptyOrNullString(String s) @ParameterizedTest @NullSource - void testConvertToInteger_whenNullString(String s) + void toInt_whenNotPrimitive_andNullString_returnsNull(String s) { Integer converted = this.converter.convert(s, Integer.class); assertThat(converted).isNull(); @@ -416,13 +416,13 @@ void testConvertToInteger_whenNullString(String s) @ParameterizedTest @EmptySource - void testConvertToInteger_whenEmptyString(String s) + void toInt_whenNotPrimitive_andEmptyString_returnsZero(String s) { Integer converted = this.converter.convert(s, Integer.class); assertThat(converted).isZero(); } - private static Stream testLongParams() { + private static Stream toLongParams() { return Stream.of( Arguments.of("-32768", -32768L), Arguments.of("32767", 32767L), @@ -446,22 +446,22 @@ private static Stream testLongParams() { } @ParameterizedTest - @MethodSource("testLongParams") - void testLong(Object value, Long expectedResult) + @MethodSource("toLongParams") + void toLong(Object value, Long expectedResult) { Long converted = this.converter.convert(value, Long.class); assertThat(converted).isEqualTo(expectedResult); } @ParameterizedTest - @MethodSource("testLongParams") - void testLong_withPrimitives(Object value, long expectedResult) + @MethodSource("toLongParams") + void toLong_usingPrimitives(Object value, long expectedResult) { long converted = this.converter.convert(value, long.class); assertThat(converted).isEqualTo(expectedResult); } - private static Stream testLong_booleanParams() { + private static Stream toLong_booleanParams() { return Stream.of( Arguments.of( true, CommonValues.LONG_ONE), Arguments.of( false, CommonValues.LONG_ZERO), @@ -472,8 +472,8 @@ private static Stream testLong_booleanParams() { } @ParameterizedTest - @MethodSource("testLong_booleanParams") - void testLong_fromBoolean(Object value, Long expectedResult) + @MethodSource("toLong_booleanParams") + void toLong_withBooleanParams_returnsCommonValues(Object value, Long expectedResult) { Long converted = this.converter.convert(value, Long.class); assertThat(converted).isSameAs(expectedResult); @@ -481,7 +481,7 @@ void testLong_fromBoolean(Object value, Long expectedResult) @ParameterizedTest @NullAndEmptySource - void testConvertToPrimitiveLong_whenEmptyOrNullString(String s) + void toLong_whenPrimitive_andNullOrEmpty_returnsZero(String s) { long converted = this.converter.convert(s, long.class); assertThat(converted).isZero(); @@ -489,7 +489,7 @@ void testConvertToPrimitiveLong_whenEmptyOrNullString(String s) @ParameterizedTest @NullSource - void testConvertToLong_whenNullString(String s) + void toLong_whenNotPrimitive_andNull_returnsNull(String s) { Long converted = this.converter.convert(s, Long.class); assertThat(converted).isNull(); @@ -497,14 +497,14 @@ void testConvertToLong_whenNullString(String s) @ParameterizedTest @EmptySource - void testConvertTLong_whenEmptyString(String s) + void toLong_whenNotPrimitive_andEmptyString_returnsZero(String s) { Long converted = this.converter.convert(s, Long.class); assertThat(converted).isZero(); } @Test - void testLong_fromDate() + void toLong_fromDate() { Date date = Date.from(Instant.now()); Long converted = this.converter.convert(date, Long.class); @@ -512,20 +512,14 @@ void testLong_fromDate() } @Test - void testLong_fromCalendar() + void toLong_fromCalendar() { Calendar date = Calendar.getInstance(); Long converted = this.converter.convert(date, Long.class); assertThat(converted).isEqualTo(date.getTime().getTime()); } - @Test - void testLong_fromLocalDate() - { - LocalDate localDate = LocalDate.now(); - Long converted = this.converter.convert(localDate, Long.class); - assertThat(converted).isEqualTo(localDate.toEpochDay()); - } + private static Stream testLongParams_withIllegalArguments() { @@ -625,12 +619,501 @@ void testAtomicLong_fromCalendar() assertThat(converted.get()).isEqualTo(date.getTime().getTime()); } + private static final ZoneId TOKYO = ZoneId.of("Asia/Tokyo"); + private static final ZoneId PARIS = ZoneId.of("Europe/Paris"); + private static final ZoneId CHICAGO = ZoneId.of("America/Chicago"); + private static final ZoneId NEW_YORK = ZoneId.of("America/New_York"); + private static final ZoneId LOS_ANGELES = ZoneId.of("America/Los_Angeles"); + + private static final ZoneId GMT = ZoneId.of("GMT"); + + private static Stream toBooleanParams_trueCases() { + return Stream.of( + Arguments.of("true"), + Arguments.of("True"), + Arguments.of("TRUE"), + Arguments.of("T"), + Arguments.of("t"), + Arguments.of("1"), + Arguments.of('T'), + Arguments.of('t'), + Arguments.of('1'), + Arguments.of(Short.MIN_VALUE), + Arguments.of(Short.MAX_VALUE), + Arguments.of(Integer.MAX_VALUE), + Arguments.of(Integer.MIN_VALUE), + Arguments.of(Long.MIN_VALUE), + Arguments.of(Long.MAX_VALUE), + Arguments.of(Boolean.TRUE), + Arguments.of(new BigInteger("8675309")), + Arguments.of(new BigDecimal("59.99")), + Arguments.of(Double.MIN_VALUE), + Arguments.of(Double.MAX_VALUE), + Arguments.of(Float.MIN_VALUE), + Arguments.of(Float.MAX_VALUE), + Arguments.of(-128.0d), + Arguments.of(127.0d), + Arguments.of( new AtomicInteger(75)), + Arguments.of( new AtomicInteger(1)), + Arguments.of( new AtomicInteger(Integer.MAX_VALUE)), + Arguments.of( new AtomicLong(Long.MAX_VALUE)) + ); + } + + @ParameterizedTest + @MethodSource("toBooleanParams_trueCases") + void testToBoolean_trueCases(Object input) { + assertThat(this.converter.convert(input, boolean.class)).isTrue(); + } + + private static Stream toBooleanParams_falseCases() { + return Stream.of( + Arguments.of("false"), + Arguments.of("f"), + Arguments.of("F"), + Arguments.of("FALSE"), + Arguments.of("9"), + Arguments.of("0"), + Arguments.of('F'), + Arguments.of('f'), + Arguments.of('0'), + Arguments.of(Character.MAX_VALUE), + Arguments.of((byte)0), + Arguments.of((short)0), + Arguments.of(0), + Arguments.of(0L), + Arguments.of(BigInteger.ZERO), + Arguments.of(BigDecimal.ZERO), + Arguments.of(0.0f), + Arguments.of(0.0d), + Arguments.of( new AtomicInteger(0)), + Arguments.of( new AtomicLong(0)) + ); + } + + @ParameterizedTest + @MethodSource("toBooleanParams_falseCases") + void testToBoolean_falseCases(Object input) { + assertThat(this.converter.convert(input, boolean.class)).isFalse(); + } + + + private static Stream epochMillis_withLocalDateTimeInformation() { + return Stream.of( + Arguments.of(1687622249729L, TOKYO, LocalDateTime.of(2023, 6, 25, 0, 57, 29, 729000000)), + Arguments.of(1687622249729L, PARIS, LocalDateTime.of(2023, 6, 24, 17, 57, 29, 729000000)), + Arguments.of(1687622249729L, GMT, LocalDateTime.of(2023, 6, 24, 15, 57, 29, 729000000)), + Arguments.of(1687622249729L, NEW_YORK, LocalDateTime.of(2023, 6, 24, 11, 57, 29, 729000000)), + Arguments.of(1687622249729L, CHICAGO, LocalDateTime.of(2023, 6, 24, 10, 57, 29, 729000000)), + Arguments.of(1687622249729L, LOS_ANGELES, LocalDateTime.of(2023, 6, 24, 8, 57, 29, 729000000)), + Arguments.of(946702799959L, TOKYO, LocalDateTime.of(2000, 1, 1, 13, 59, 59, 959000000)), + Arguments.of(946702799959L, PARIS, LocalDateTime.of(2000, 1, 1, 5, 59, 59, 959000000)), + Arguments.of(946702799959L, GMT, LocalDateTime.of(2000, 1, 1, 4, 59, 59, 959000000)), + Arguments.of(946702799959L, NEW_YORK, LocalDateTime.of(1999, 12, 31, 23, 59, 59, 959000000)), + Arguments.of(946702799959L, CHICAGO, LocalDateTime.of(1999, 12, 31, 22, 59, 59, 959000000)), + Arguments.of(946702799959L, LOS_ANGELES, LocalDateTime.of(1999, 12, 31, 20, 59, 59, 959000000)) + + ); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testCalendarToLocalDateTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(epochMilli); + + LocalDateTime localDateTime = this.converter.convert(calendar, LocalDateTime.class, createConvertOptions(zoneId, zoneId)); + + assertThat(localDateTime).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testCalendarToLocalDateTime_whenCalendarTimeZoneMatches(long epochMilli, ZoneId zoneId, LocalDateTime expected) { + Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone(zoneId)); + calendar.setTimeInMillis(epochMilli); + + LocalDateTime localDateTime = this.converter.convert(calendar, LocalDateTime.class, createConvertOptions(zoneId, zoneId)); + assertThat(localDateTime).isEqualTo(expected); + } + + @Test + void testCalendarToLocalDateTime_whenCalendarTimeZoneDoesNotMatch() { + Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone(NEW_YORK)); + calendar.setTimeInMillis(1687622249729L); + + LocalDateTime localDateTime = this.converter.convert(calendar, LocalDateTime.class, createConvertOptions(NEW_YORK, TOKYO)); + + System.out.println(localDateTime); + + assertThat(localDateTime) + .hasYear(2023) + .hasMonthValue(6) + .hasDayOfMonth(25) + .hasHour(0) + .hasMinute(57) + .hasSecond(29) + .hasNano(729000000); + } + + @Test + void testCalendar_roundTrip() { + + // Create LocalDateTime as CHICAGO TIME. + GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone(CHICAGO)); + calendar.setTimeInMillis(1687622249729L); + + assertThat(calendar.get(Calendar.MONTH)).isEqualTo(5); + assertThat(calendar.get(Calendar.DAY_OF_MONTH)).isEqualTo(24); + assertThat(calendar.get(Calendar.YEAR)).isEqualTo(2023); + assertThat(calendar.get(Calendar.HOUR_OF_DAY)).isEqualTo(10); + assertThat(calendar.get(Calendar.MINUTE)).isEqualTo(57); + assertThat(calendar.getTimeInMillis()).isEqualTo(1687622249729L); + + // Convert calendar calendar to TOKYO LocalDateTime + LocalDateTime localDateTime = this.converter.convert(calendar, LocalDateTime.class, createConvertOptions(CHICAGO, TOKYO)); + + assertThat(localDateTime) + .hasYear(2023) + .hasMonthValue(6) + .hasDayOfMonth(25) + .hasHour(0) + .hasMinute(57) + .hasSecond(29) + .hasNano(729000000); + + // Convert Tokyo local date time to CHICAGO Calendar + // We don't know the source ZoneId we are trying to convert. + Calendar actual = this.converter.convert(localDateTime, Calendar.class, createConvertOptions(TOKYO, CHICAGO)); + + assertThat(actual.get(Calendar.MONTH)).isEqualTo(5); + assertThat(actual.get(Calendar.DAY_OF_MONTH)).isEqualTo(24); + assertThat(actual.get(Calendar.YEAR)).isEqualTo(2023); + assertThat(actual.get(Calendar.HOUR_OF_DAY)).isEqualTo(10); + assertThat(actual.get(Calendar.MINUTE)).isEqualTo(57); + assertThat(actual.getTimeInMillis()).isEqualTo(1687622249729L); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testZonedDateTimeToLocalDateTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + ZonedDateTime time = Instant.ofEpochMilli(epochMilli).atZone(zoneId); + + LocalDateTime localDateTime = this.converter.convert(time, LocalDateTime.class, createConvertOptions(zoneId, zoneId)); + + assertThat(time.toInstant().toEpochMilli()).isEqualTo(epochMilli); + assertThat(localDateTime).isEqualTo(expected); + } + + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testZonedDateTimeToLong(long epochMilli, ZoneId zoneId, LocalDateTime localDateTime) + { + ZonedDateTime time = ZonedDateTime.of(localDateTime, zoneId); + + long instant = this.converter.convert(time, long.class, createConvertOptions(zoneId, zoneId)); + + assertThat(instant).isEqualTo(epochMilli); + } + + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testLongToLocalDateTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + LocalDateTime localDateTime = this.converter.convert(epochMilli, LocalDateTime.class, createConvertOptions(null, zoneId)); + assertThat(localDateTime).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testAtomicLongToLocalDateTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + AtomicLong time = new AtomicLong(epochMilli); + + LocalDateTime localDateTime = this.converter.convert(time, LocalDateTime.class, createConvertOptions(null, zoneId)); + assertThat(localDateTime).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testBigIntegerToLocalDateTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + BigInteger bi = BigInteger.valueOf(epochMilli); + + LocalDateTime localDateTime = this.converter.convert(bi, LocalDateTime.class, createConvertOptions(null, zoneId)); + assertThat(localDateTime).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testBigDecimalToLocalDateTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + BigDecimal bd = BigDecimal.valueOf(epochMilli); + + LocalDateTime localDateTime = this.converter.convert(bd, LocalDateTime.class, createConvertOptions(null, zoneId)); + assertThat(localDateTime).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testInstantToLocalDateTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Instant instant = Instant.ofEpochMilli(epochMilli); + LocalDateTime localDateTime = this.converter.convert(instant, LocalDateTime.class, createConvertOptions(null, zoneId)); + assertThat(localDateTime).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testDateToLocalDateTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Date date = new Date(epochMilli); + LocalDateTime localDateTime = this.converter.convert(date, LocalDateTime.class, createConvertOptions(null, zoneId)); + assertThat(localDateTime).isEqualTo(expected); + } + + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testSqlDateToLocalDateTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + java.sql.Date date = new java.sql.Date(epochMilli); + LocalDateTime localDateTime = this.converter.convert(date, LocalDateTime.class, createConvertOptions(null, zoneId)); + assertThat(localDateTime).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testTimestampToLocalDateTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Timestamp date = new Timestamp(epochMilli); + LocalDateTime localDateTime = this.converter.convert(date, LocalDateTime.class, createConvertOptions(null, zoneId)); + assertThat(localDateTime).isEqualTo(expected); + } + + + private static Stream epochMillis_withLocalDateInformation() { + return Stream.of( + Arguments.of(1687622249729L, TOKYO, LocalDate.of(2023, 6, 25)), + Arguments.of(1687622249729L, PARIS, LocalDate.of(2023, 6, 24)), + Arguments.of(1687622249729L, GMT, LocalDate.of(2023, 6, 24)), + Arguments.of(1687622249729L, NEW_YORK, LocalDate.of(2023, 6, 24)), + Arguments.of(1687622249729L, CHICAGO, LocalDate.of(2023, 6, 24)), + Arguments.of(1687622249729L, LOS_ANGELES, LocalDate.of(2023, 6, 24)), + Arguments.of(946702799959L, TOKYO, LocalDate.of(2000, 1, 1)), + Arguments.of(946702799959L, PARIS, LocalDate.of(2000, 1, 1)), + Arguments.of(946702799959L, GMT, LocalDate.of(2000, 1, 1)), + Arguments.of(946702799959L, NEW_YORK, LocalDate.of(1999, 12, 31)), + Arguments.of(946702799959L, CHICAGO, LocalDate.of(1999, 12, 31)), + Arguments.of(946702799959L, LOS_ANGELES, LocalDate.of(1999, 12, 31)) + + ); + } + + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateInformation") + void testCalendarToLocalDate(long epochMilli, ZoneId zoneId, LocalDate expected) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(epochMilli); + + LocalDate localDate = this.converter.convert(calendar, LocalDate.class, createConvertOptions(null, zoneId)); + assertThat(localDate).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateInformation") + void testCalendarToLocalDate_whenCalendarTimeZoneMatches(long epochMilli, ZoneId zoneId, LocalDate expected) { + Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone(zoneId)); + calendar.setTimeInMillis(epochMilli); + + LocalDate localDate = this.converter.convert(calendar, LocalDate.class, createConvertOptions(null, zoneId)); + assertThat(localDate).isEqualTo(expected); + } + @Test - void testAtomicLong_fromLocalDate() + void testCalendarToLocalDate_whenCalendarTimeZoneDoesNotMatchTarget_convertsTimeCorrectly() { + Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone(NEW_YORK)); + calendar.setTimeInMillis(1687622249729L); + + LocalDate localDate = this.converter.convert(calendar, LocalDate.class, createConvertOptions(null, TOKYO)); + + assertThat(localDate) + .hasYear(2023) + .hasMonthValue(6) + .hasDayOfMonth(25); + } + + @Test + void testCalendar_testData() { + + // Create LocalDateTime as CHICAGO TIME. + GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone(CHICAGO)); + calendar.setTimeInMillis(1687622249729L); + + assertThat(calendar.get(Calendar.MONTH)).isEqualTo(5); + assertThat(calendar.get(Calendar.DAY_OF_MONTH)).isEqualTo(24); + assertThat(calendar.get(Calendar.YEAR)).isEqualTo(2023); + assertThat(calendar.get(Calendar.HOUR_OF_DAY)).isEqualTo(10); + assertThat(calendar.get(Calendar.MINUTE)).isEqualTo(57); + assertThat(calendar.getTimeInMillis()).isEqualTo(1687622249729L); + + // Convert calendar calendar to TOKYO LocalDateTime + LocalDateTime localDateTime = this.converter.convert(calendar, LocalDateTime.class, createConvertOptions(CHICAGO, TOKYO)); + + assertThat(localDateTime) + .hasYear(2023) + .hasMonthValue(6) + .hasDayOfMonth(25) + .hasHour(0) + .hasMinute(57) + .hasSecond(29) + .hasNano(729000000); + + // Convert Tokyo local date time to CHICAGO Calendar + // We don't know the source ZoneId we are trying to convert. + Calendar actual = this.converter.convert(localDateTime, Calendar.class, createConvertOptions(TOKYO, CHICAGO)); + + assertThat(actual.get(Calendar.MONTH)).isEqualTo(5); + assertThat(actual.get(Calendar.DAY_OF_MONTH)).isEqualTo(24); + assertThat(actual.get(Calendar.YEAR)).isEqualTo(2023); + assertThat(actual.get(Calendar.HOUR_OF_DAY)).isEqualTo(10); + assertThat(actual.get(Calendar.MINUTE)).isEqualTo(57); + assertThat(actual.getTimeInMillis()).isEqualTo(1687622249729L); + } + + + @Test + void toLong_fromLocalDate() { LocalDate localDate = LocalDate.now(); - Long converted = this.converter.convert(localDate, Long.class); - assertThat(converted).isEqualTo(localDate.toEpochDay()); + ConverterOptions options = chicagoZone(); + Long converted = this.converter.convert(localDate, Long.class, options); + assertThat(converted).isEqualTo(localDate.atStartOfDay(options.getZoneId()).toInstant().toEpochMilli()); + } + + + + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateInformation") + void testLongToLocalDate(long epochMilli, ZoneId zoneId, LocalDate expected) + { + LocalDate localDate = this.converter.convert(epochMilli, LocalDate.class, createConvertOptions(null, zoneId)); + + assertThat(localDate).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateInformation") + void testZonedDateTimeToLocalDate(long epochMilli, ZoneId zoneId, LocalDate expected) + { + LocalDate localDate = this.converter.convert(epochMilli, LocalDate.class, createConvertOptions(null, zoneId)); + + assertThat(localDate).isEqualTo(expected); + } + + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateInformation") + void testInstantToLocalDate(long epochMilli, ZoneId zoneId, LocalDate expected) + { + Instant instant = Instant.ofEpochMilli(epochMilli); + LocalDate localDate = this.converter.convert(instant, LocalDate.class, createConvertOptions(null, zoneId)); + + assertThat(localDate).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateInformation") + void testDateToLocalDate(long epochMilli, ZoneId zoneId, LocalDate expected) + { + Date date = new Date(epochMilli); + LocalDate localDate = this.converter.convert(date, LocalDate.class, createConvertOptions(null, zoneId)); + + assertThat(localDate).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateInformation") + void testSqlDateToLocalDate(long epochMilli, ZoneId zoneId, LocalDate expected) + { + java.sql.Date date = new java.sql.Date(epochMilli); + LocalDate localDate = this.converter.convert(date, LocalDate.class, createConvertOptions(null, zoneId)); + + assertThat(localDate).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateInformation") + void testTimestampToLocalDate(long epochMilli, ZoneId zoneId, LocalDate expected) + { + Timestamp date = new Timestamp(epochMilli); + LocalDate localDate = this.converter.convert(date, LocalDate.class, createConvertOptions(null, zoneId)); + + assertThat(localDate).isEqualTo(expected); + } + + + private static final LocalDateTime LDT_TOKYO_1 = LocalDateTime.of(2023, 6, 25, 0, 57, 29, 729000000); + private static final LocalDateTime LDT_PARIS_1 = LocalDateTime.of(2023, 6, 24, 17, 57, 29, 729000000); + private static final LocalDateTime LDT_NY_1 = LocalDateTime.of(2023, 6, 24, 11, 57, 29, 729000000); + private static final LocalDateTime LDT_LA_1 = LocalDateTime.of(2023, 6, 24, 8, 57, 29, 729000000); + + private static Stream localDateTimeConversion_params() { + return Stream.of( + Arguments.of(1687622249729L, NEW_YORK, LDT_NY_1, TOKYO, LDT_TOKYO_1), + Arguments.of(1687622249729L, LOS_ANGELES, LDT_LA_1, PARIS, LDT_PARIS_1) + ); + } + + + @ParameterizedTest + @MethodSource("localDateTimeConversion_params") + void testLocalDateTimeToLong(long epochMilli, ZoneId sourceZoneId, LocalDateTime initial, ZoneId targetZoneId, LocalDateTime expected) + { + long milli = this.converter.convert(initial, long.class, createConvertOptions(sourceZoneId, targetZoneId)); + assertThat(milli).isEqualTo(epochMilli); + + LocalDateTime actual = this.converter.convert(milli, LocalDateTime.class, createConvertOptions(sourceZoneId, targetZoneId)); + assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("localDateTimeConversion_params") + void testLocalDateTimeToAtomicLong(long epochMilli, ZoneId sourceZoneId, LocalDateTime initial, ZoneId targetZoneId, LocalDateTime expected) + { + AtomicLong milli = this.converter.convert(initial, AtomicLong.class, createConvertOptions(sourceZoneId, targetZoneId)); + assertThat(milli.longValue()).isEqualTo(epochMilli); + + LocalDateTime actual = this.converter.convert(milli, LocalDateTime.class, createConvertOptions(sourceZoneId, targetZoneId)); + assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("localDateTimeConversion_params") + void testLocalDateTimeToBigInteger(long epochMilli, ZoneId sourceZoneId, LocalDateTime initial, ZoneId targetZoneId, LocalDateTime expected) + { + BigInteger milli = this.converter.convert(initial, BigInteger.class, createConvertOptions(sourceZoneId, targetZoneId)); + assertThat(milli.longValue()).isEqualTo(epochMilli); + + LocalDateTime actual = this.converter.convert(milli, LocalDateTime.class, createConvertOptions(sourceZoneId, targetZoneId)); + assertThat(actual).isEqualTo(expected); + + } + + @ParameterizedTest + @MethodSource("localDateTimeConversion_params") + void testLocalDateTimeToBigDecimal(long epochMilli, ZoneId sourceZoneId, LocalDateTime initial, ZoneId targetZoneId, LocalDateTime expected) + { + BigDecimal milli = this.converter.convert(initial, BigDecimal.class, createConvertOptions(sourceZoneId, targetZoneId)); + assertThat(milli.longValue()).isEqualTo(epochMilli); + + LocalDateTime actual = this.converter.convert(milli, LocalDateTime.class, createConvertOptions(sourceZoneId, targetZoneId)); + assertThat(actual).isEqualTo(expected); } @@ -828,33 +1311,24 @@ void testConvertToBigDecimal_withIllegalArguments(Object value, String partialMe .withMessageContaining(partialMessage); } - /** - * - * assertEquals(new BigInteger("3"), this.converter.convert(new BigDecimal("3.14"), BigInteger.class)); - * assertEquals(new BigInteger("8675309"), this.converter.convert(new BigInteger("8675309"), BigInteger.class)); - * assertEquals(new BigInteger("75"), this.converter.convert((short) 75, BigInteger.class)); - * assertEquals(BigInteger.ONE, this.converter.convert(true, BigInteger.class)); - * assertSame(BigInteger.ONE, this.converter.convert(true, BigInteger.class)); - * assertEquals(BigInteger.ZERO, this.converter.convert(false, BigInteger.class)); - * assertSame(BigInteger.ZERO, this.converter.convert(false, BigInteger.class)); - * assertEquals(converter.convert(new BigInteger("314159"), Boolean.class), true); - * assertEquals(new BigInteger("11"), converter.convert("11.5", BigInteger.class)); - */ private static Stream testBigIntegerParams() { return Stream.of( Arguments.of("-32768", BigInteger.valueOf(-32768L)), Arguments.of("32767", BigInteger.valueOf(32767L)), + Arguments.of((short)75, BigInteger.valueOf(75)), Arguments.of(Byte.MIN_VALUE, BigInteger.valueOf((-128L)), - Arguments.of(Byte.MAX_VALUE, BigInteger.valueOf(127L)), - Arguments.of(Short.MIN_VALUE, BigInteger.valueOf(-32768L)), - Arguments.of(Short.MAX_VALUE, BigInteger.valueOf(32767L)), - Arguments.of(Integer.MIN_VALUE, BigInteger.valueOf(-2147483648L)), - Arguments.of(Integer.MAX_VALUE, BigInteger.valueOf(2147483647L)), - Arguments.of(Long.MIN_VALUE, BigInteger.valueOf(-9223372036854775808L)), - Arguments.of(Long.MAX_VALUE, BigInteger.valueOf(9223372036854775807L)), - Arguments.of(-128.0f, BigInteger.valueOf(-128)), - Arguments.of(127.0f, BigInteger.valueOf(127)), - Arguments.of(-128.0d, BigInteger.valueOf(-128))), + Arguments.of(Byte.MAX_VALUE, BigInteger.valueOf(127L)), + Arguments.of(Short.MIN_VALUE, BigInteger.valueOf(-32768L)), + Arguments.of(Short.MAX_VALUE, BigInteger.valueOf(32767L)), + Arguments.of(Integer.MIN_VALUE, BigInteger.valueOf(-2147483648L)), + Arguments.of(Integer.MAX_VALUE, BigInteger.valueOf(2147483647L)), + Arguments.of(Long.MIN_VALUE, BigInteger.valueOf(-9223372036854775808L)), + Arguments.of(Long.MAX_VALUE, BigInteger.valueOf(9223372036854775807L)), + Arguments.of(-128.192f, BigInteger.valueOf(-128)), + Arguments.of(127.5698f, BigInteger.valueOf(127)), + Arguments.of(-128.0d, BigInteger.valueOf(-128))), + Arguments.of(3.14d, BigInteger.valueOf(3)), + Arguments.of("11.5", new BigInteger("11")), Arguments.of(127.0d, BigInteger.valueOf(127)), Arguments.of( new BigDecimal("100"), new BigInteger("100")), Arguments.of( new BigInteger("120"), new BigInteger("120")), @@ -928,7 +1402,7 @@ void testConvertToBigInteger_withIllegalArguments(Object value, String partialMe @ParameterizedTest - @MethodSource("testIntParams") + @MethodSource("toIntParams") void testAtomicInteger(Object value, int expectedResult) { AtomicInteger converted = this.converter.convert(value, AtomicInteger.class); @@ -959,7 +1433,7 @@ void testAtomicInteger_withBooleanTypes(Object value, AtomicInteger expected) { assertThat(converted.get()).isEqualTo(expected.get()); } - private static Stream testAtomicinteger_withIllegalArguments_params() { + private static Stream testAtomicInteger_withIllegalArguments_params() { return Stream.of( Arguments.of("45badNumber", "not parseable"), Arguments.of(ZoneId.systemDefault(), "Unsupported conversion"), @@ -967,15 +1441,187 @@ private static Stream testAtomicinteger_withIllegalArguments_params() } @ParameterizedTest - @MethodSource("testAtomicinteger_withIllegalArguments_params") - void testAtomicinteger_withIllegalArguments(Object value, String partialMessage) { + @MethodSource("testAtomicInteger_withIllegalArguments_params") + void testAtomicInteger_withIllegalArguments(Object value, String partialMessage) { assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy(() -> this.converter.convert(value, BigInteger.class)) .withMessageContaining(partialMessage); } + private static Stream epochMilli_exampleOneParams() { + return Stream.of( + Arguments.of(1705601070270L), + Arguments.of( new Long(1705601070270L)), + Arguments.of( new AtomicLong(1705601070270L)), + Arguments.of( 1705601070270.798659898d), + Arguments.of( BigInteger.valueOf(1705601070270L)), + Arguments.of( BigDecimal.valueOf(1705601070270L)), + Arguments.of("1705601070270") + ); + } + + @ParameterizedTest + @MethodSource("epochMilli_exampleOneParams") + void testDate(Object value) { + Date expected = new Date(1705601070270L); + Date converted = this.converter.convert(value, Date.class); + assertThat(converted).isEqualTo(expected); + } + + // float doesn't have enough significant digits to accurately represent today's dates + private static Stream conversionsWithPrecisionLoss_primitiveParams() { + return Stream.of( + // double -> + Arguments.of( 1705601070270.89765d, float.class, 1705601010100f), + Arguments.of( 1705601070270.89765d, Float.class, 1705601010100f), + Arguments.of( 1705601070270.89765d, byte.class, (byte)-1), + Arguments.of( 1705601070270.89765d, Byte.class, (byte)-1), + Arguments.of( 1705601070270.89765d, short.class, (short)-1), + Arguments.of( 1705601070270.89765d, Short.class, (short)-1), + Arguments.of( 1705601070270.89765d, int.class, 2147483647), + Arguments.of( 1705601070270.89765d, Integer.class, 2147483647), + Arguments.of( 1705601070270.89765d, long.class, 1705601070270L), + Arguments.of( 1705601070270.89765d, Long.class, 1705601070270L), + + // float -> + Arguments.of( 65679.6f, byte.class, (byte)-113), + Arguments.of( 65679.6f, Byte.class, (byte)-113), + Arguments.of( 65679.6f, short.class, (short)143), + Arguments.of( 65679.6f, Short.class, (short)143), + Arguments.of( 65679.6f, int.class, 65679), + Arguments.of( 65679.6f, Integer.class, 65679), + Arguments.of( 65679.6f, long.class, 65679L), + Arguments.of( 65679.6f, Long.class, 65679L), + + // long -> + Arguments.of( new BigInteger("92233720368547738079919"), double.class, 92233720368547740000000.0d), + Arguments.of( new BigInteger("92233720368547738079919"), Double.class, 92233720368547740000000.0d), + Arguments.of( new BigInteger("92233720368547738079919"), float.class, 92233720368547760000000f), + Arguments.of( new BigInteger("92233720368547738079919"), Float.class, 92233720368547760000000f), + Arguments.of( new BigInteger("92233720368547738079919"), Byte.class, (byte)-81), + Arguments.of( new BigInteger("92233720368547738079919"), byte.class, (byte)-81), + Arguments.of( new BigInteger("92233720368547738079919"), short.class, (short)-11601), + Arguments.of( new BigInteger("92233720368547738079919"), Short.class, (short)-11601), + Arguments.of( new BigInteger("92233720368547738079919"), int.class, -20000081), + Arguments.of( new BigInteger("92233720368547738079919"), Integer.class, -20000081), + Arguments.of( new BigInteger("92233720368547738079919"), long.class, -20000081L), + Arguments.of( new BigInteger("92233720368547738079919"), Long.class, -20000081L), + + + // long -> + Arguments.of( 9223372036854773807L, double.class, 9223372036854773800.0d), + Arguments.of( 9223372036854773807L, Double.class, 9223372036854773800.0d), + Arguments.of( 9223372036854773807L, float.class, 9223372036854776000.0f), + Arguments.of( 9223372036854773807L, Float.class, 9223372036854776000.0f), + Arguments.of( 9223372036854773807L, Byte.class, (byte)47), + Arguments.of( 9223372036854773807L, byte.class, (byte)47), + Arguments.of( 9223372036854773807L, short.class, (short)-2001), + Arguments.of( 9223372036854773807L, Short.class, (short)-2001), + Arguments.of( 9223372036854773807L, int.class, -2001), + Arguments.of( 9223372036854773807L, Integer.class, -2001), + + // AtomicLong -> + Arguments.of( new AtomicLong(9223372036854773807L), double.class, 9223372036854773800.0d), + Arguments.of( new AtomicLong(9223372036854773807L), Double.class, 9223372036854773800.0d), + Arguments.of( new AtomicLong(9223372036854773807L), float.class, 9223372036854776000.0f), + Arguments.of( new AtomicLong(9223372036854773807L), Float.class, 9223372036854776000.0f), + Arguments.of( new AtomicLong(9223372036854773807L), Byte.class, (byte)47), + Arguments.of( new AtomicLong(9223372036854773807L), byte.class, (byte)47), + Arguments.of( new AtomicLong(9223372036854773807L), short.class, (short)-2001), + Arguments.of( new AtomicLong(9223372036854773807L), Short.class, (short)-2001), + Arguments.of( new AtomicLong(9223372036854773807L), int.class, -2001), + Arguments.of( new AtomicLong(9223372036854773807L), Integer.class, -2001), + + Arguments.of( 2147473647, float.class, 2147473664.0f), + Arguments.of( 2147473647, Float.class, 2147473664.0f), + Arguments.of( 2147473647, Byte.class, (byte)-17), + Arguments.of( 2147473647, byte.class, (byte)-17), + Arguments.of( 2147473647, short.class, (short)-10001), + Arguments.of( 2147473647, Short.class, (short)-10001), + + // AtomicInteger -> + Arguments.of( new AtomicInteger(2147473647), float.class, 2147473664.0f), + Arguments.of( new AtomicInteger(2147473647), Float.class, 2147473664.0f), + Arguments.of( new AtomicInteger(2147473647), Byte.class, (byte)-17), + Arguments.of( new AtomicInteger(2147473647), byte.class, (byte)-17), + Arguments.of( new AtomicInteger(2147473647), short.class, (short)-10001), + Arguments.of( new AtomicInteger(2147473647), Short.class, (short)-10001), + + // short -> + Arguments.of( (short)62212, Byte.class, (byte)4), + Arguments.of( (short)62212, byte.class, (byte)4) + ); + } + + @ParameterizedTest + @MethodSource("conversionsWithPrecisionLoss_primitiveParams") + void conversionsWithPrecisionLoss_primitives(Object value, Class c, Object expected) { + Object converted = this.converter.convert(value, c); + assertThat(converted).isEqualTo(expected); + } + + + // float doesn't have enough significant digits to accurately represent today's dates + private static Stream conversionsWithPrecisionLoss_toAtomicIntegerParams() { + return Stream.of( + Arguments.of( 1705601070270.89765d, new AtomicInteger(2147483647)), + Arguments.of( 65679.6f, new AtomicInteger(65679)), + Arguments.of( 9223372036854773807L, new AtomicInteger(-2001)), + Arguments.of( new AtomicLong(9223372036854773807L), new AtomicInteger(-2001)) + ); + } + + @ParameterizedTest + @MethodSource("conversionsWithPrecisionLoss_toAtomicIntegerParams") + void conversionsWithPrecisionLoss_toAtomicInteger(Object value, AtomicInteger expected) { + AtomicInteger converted = this.converter.convert(value, AtomicInteger.class); + assertThat(converted.get()).isEqualTo(expected.get()); + } + + private static Stream conversionsWithPrecisionLoss_toAtomicLongParams() { + return Stream.of( + // double -> + Arguments.of( 1705601070270.89765d, new AtomicLong(1705601070270L)), + Arguments.of( 65679.6f, new AtomicLong(65679L)) + ); + } + + @ParameterizedTest + @MethodSource("conversionsWithPrecisionLoss_toAtomicLongParams") + void conversionsWithPrecisionLoss_toAtomicLong(Object value, AtomicLong expected) { + AtomicLong converted = this.converter.convert(value, AtomicLong.class); + assertThat(converted.get()).isEqualTo(expected.get()); + } + + + + + // I think parsing a string double into date is gone now. Arguments.of("11.5", new Date(11)), + private static Stream extremeDateParams() { + return Stream.of( + Arguments.of((short)75, new Date(75)), + Arguments.of(Byte.MIN_VALUE, new Date(Byte.MIN_VALUE)), + Arguments.of(Byte.MAX_VALUE, new Date(Byte.MAX_VALUE)), + Arguments.of(Short.MIN_VALUE, new Date(Short.MIN_VALUE)), + Arguments.of(Short.MAX_VALUE, new Date(Short.MAX_VALUE)), + Arguments.of(Integer.MIN_VALUE, new Date(Integer.MIN_VALUE)), + Arguments.of(Integer.MAX_VALUE, new Date(Integer.MAX_VALUE)), + Arguments.of(Long.MIN_VALUE,new Date(Long.MIN_VALUE)), + Arguments.of(Long.MAX_VALUE, new Date(Long.MAX_VALUE)), + Arguments.of(127.0d, new Date(127)), + Arguments.of( new AtomicInteger(25), new Date(25)) + ); + } + + @ParameterizedTest + @MethodSource("extremeDateParams") + void testExtremeDateParams(Object value, Date expected) { + Date converted = this.converter.convert(value, Date.class); + assertThat(converted).isEqualTo(expected); + } + @Test - void testDate() + void testDateFromOthers() { // Date to Date Date utilNow = new Date(); @@ -1220,120 +1866,7 @@ void testCalendar() assertEquals(now.getTime(), bigDec.longValue()); } - @Test - void testLocalDateToOthers() - { - // Date to LocalDate - Calendar calendar = Calendar.getInstance(); - calendar.clear(); - calendar.set(2020, 8, 30, 0, 0, 0); - Date now = calendar.getTime(); - LocalDate localDate = this.converter.convert(now, LocalDate.class); - assertEquals(localDateToMillis(localDate, ZoneId.systemDefault()), now.getTime()); - - // LocalDate to LocalDate - identity check - LocalDate x = this.converter.convert(localDate, LocalDate.class); - assert localDate == x; - - // LocalDateTime to LocalDate - LocalDateTime ldt = LocalDateTime.of(2020, 8, 30, 0, 0, 0); - x = this.converter.convert(ldt, LocalDate.class); - assert localDateTimeToMillis(ldt, ZoneId.systemDefault()) == localDateToMillis(x, ZoneId.systemDefault()); - - // ZonedDateTime to LocalDate - ZonedDateTime zdt = ZonedDateTime.of(2020, 8, 30, 0, 0, 0, 0, ZoneId.systemDefault()); - x = this.converter.convert(zdt, LocalDate.class); - assert zonedDateTimeToMillis(zdt) == localDateToMillis(x, ZoneId.systemDefault()); - - // Calendar to LocalDate - x = this.converter.convert(calendar, LocalDate.class); - assert localDateToMillis(localDate, ZoneId.systemDefault()) == calendar.getTime().getTime(); - - // SqlDate to LocalDate - java.sql.Date sqlDate = this.converter.convert(now, java.sql.Date.class); - localDate = this.converter.convert(sqlDate, LocalDate.class); - assertEquals(localDateToMillis(localDate, ZoneId.systemDefault()), sqlDate.getTime()); - - // Timestamp to LocalDate - Timestamp timestamp = this.converter.convert(now, Timestamp.class); - localDate = this.converter.convert(timestamp, LocalDate.class); - assertEquals(localDateToMillis(localDate, ZoneId.systemDefault()), timestamp.getTime()); - - LocalDate nowDate = LocalDate.now(); - // Long to LocalDate - localDate = this.converter.convert(nowDate.toEpochDay(), LocalDate.class); - assertEquals(localDate, nowDate); - - // AtomicLong to LocalDate - AtomicLong atomicLong = new AtomicLong(nowDate.toEpochDay()); - localDate = this.converter.convert(atomicLong, LocalDate.class); - assertEquals(localDate, nowDate); - - // String to LocalDate - String strDate = this.converter.convert(now, String.class); - localDate = this.converter.convert(strDate, LocalDate.class); - String strDate2 = this.converter.convert(localDate, String.class); - assert strDate.startsWith(strDate2); - - // BigInteger to LocalDate - BigInteger bigInt = new BigInteger("" + nowDate.toEpochDay()); - localDate = this.converter.convert(bigInt, LocalDate.class); - assertEquals(localDate, nowDate); - - // BigDecimal to LocalDate - BigDecimal bigDec = new BigDecimal(nowDate.toEpochDay()); - localDate = this.converter.convert(bigDec, LocalDate.class); - assertEquals(localDate, nowDate); - - // Other direction --> LocalDate to other date types - - // LocalDate to Date - localDate = this.converter.convert(now, LocalDate.class); - Date date = this.converter.convert(localDate, Date.class); - assertEquals(localDateToMillis(localDate, ZoneId.systemDefault()), date.getTime()); - - // LocalDate to SqlDate - sqlDate = this.converter.convert(localDate, java.sql.Date.class); - assertEquals(localDateToMillis(localDate, ZoneId.systemDefault()), sqlDate.getTime()); - - // LocalDate to Timestamp - timestamp = this.converter.convert(localDate, Timestamp.class); - assertEquals(localDateToMillis(localDate, ZoneId.systemDefault()), timestamp.getTime()); - // LocalDate to Long - long tnow = this.converter.convert(localDate, long.class); - assertEquals(localDate.toEpochDay(), tnow); - - // LocalDate to AtomicLong - atomicLong = this.converter.convert(localDate, AtomicLong.class); - assertEquals(localDate.toEpochDay(), atomicLong.get()); - - // LocalDate to String - strDate = this.converter.convert(localDate, String.class); - strDate2 = this.converter.convert(now, String.class); - assert strDate2.startsWith(strDate); - - // LocalDate to BigInteger - bigInt = this.converter.convert(localDate, BigInteger.class); - LocalDate nd = LocalDate.ofEpochDay(bigInt.longValue()); - assertEquals(localDate, nd); - - // LocalDate to BigDecimal - bigDec = this.converter.convert(localDate, BigDecimal.class); - nd = LocalDate.ofEpochDay(bigDec.longValue()); - assertEquals(localDate, nd); - - // Error handling - try { - this.converter.convert("2020-12-40", LocalDate.class); - fail(); - } - catch (IllegalArgumentException e) { - TestUtil.assertContainsIgnoreCase(e.getMessage(), "day must be between 1 and 31"); - } - - assert this.converter.convert(null, LocalDate.class) == null; - } @Test void testStringToLocalDate() @@ -1417,236 +1950,99 @@ void testStringKeysOnMapToLocalDate() assert ld.getDayOfMonth() == 23; } - @Test - void testLocalDateTimeToOthers() - { - // Date to LocalDateTime - Calendar calendar = Calendar.getInstance(); - calendar.clear(); - calendar.set(2020, 8, 30, 13, 1, 11); - Date now = calendar.getTime(); - LocalDateTime localDateTime = this.converter.convert(now, LocalDateTime.class); - assertEquals(localDateTimeToMillis(localDateTime, ZoneId.systemDefault()), now.getTime()); - - // LocalDateTime to LocalDateTime - identity check - LocalDateTime x = this.converter.convert(localDateTime, LocalDateTime.class); - assert localDateTime == x; - - // LocalDate to LocalDateTime - LocalDate ld = LocalDate.of(2020, 8, 30); - x = this.converter.convert(ld, LocalDateTime.class); - assert localDateToMillis(ld, ZoneId.systemDefault()) == localDateTimeToMillis(x, ZoneId.systemDefault()); - - // ZonedDateTime to LocalDateTime - ZonedDateTime zdt = ZonedDateTime.of(2020, 8, 30, 13, 1, 11, 0, ZoneId.systemDefault()); - x = this.converter.convert(zdt, LocalDateTime.class); - assert zonedDateTimeToMillis(zdt) == localDateTimeToMillis(x, ZoneId.systemDefault()); - - // Calendar to LocalDateTime - x = this.converter.convert(calendar, LocalDateTime.class); - assert localDateTimeToMillis(localDateTime, ZoneId.systemDefault()) == calendar.getTime().getTime(); - - // SqlDate to LocalDateTime - java.sql.Date sqlDate = this.converter.convert(now, java.sql.Date.class); - localDateTime = this.converter.convert(sqlDate, LocalDateTime.class); - assertEquals(localDateTimeToMillis(localDateTime, ZoneId.systemDefault()), localDateToMillis(sqlDate.toLocalDate(), ZoneId.systemDefault())); - - // Timestamp to LocalDateTime - Timestamp timestamp = this.converter.convert(now, Timestamp.class); - localDateTime = this.converter.convert(timestamp, LocalDateTime.class); - assertEquals(localDateTimeToMillis(localDateTime, ZoneId.systemDefault()), timestamp.getTime()); - - // Long to LocalDateTime - localDateTime = this.converter.convert(now.getTime(), LocalDateTime.class); - assertEquals(localDateTimeToMillis(localDateTime, ZoneId.systemDefault()), now.getTime()); - - // AtomicLong to LocalDateTime - AtomicLong atomicLong = new AtomicLong(now.getTime()); - localDateTime = this.converter.convert(atomicLong, LocalDateTime.class); - assertEquals(localDateTimeToMillis(localDateTime, ZoneId.systemDefault()), now.getTime()); - - // String to LocalDateTime - String strDate = this.converter.convert(now, String.class); - localDateTime = this.converter.convert(strDate, LocalDateTime.class); - String strDate2 = this.converter.convert(localDateTime, String.class); - assert strDate.startsWith(strDate2); - - // BigInteger to LocalDateTime - BigInteger bigInt = new BigInteger("" + now.getTime()); - localDateTime = this.converter.convert(bigInt, LocalDateTime.class); - assertEquals(localDateTimeToMillis(localDateTime, ZoneId.systemDefault()), now.getTime()); - - // BigDecimal to LocalDateTime - BigDecimal bigDec = new BigDecimal(now.getTime()); - localDateTime = this.converter.convert(bigDec, LocalDateTime.class); - assertEquals(localDateTimeToMillis(localDateTime, ZoneId.systemDefault()), now.getTime()); - // Other direction --> LocalDateTime to other date types - - // LocalDateTime to Date - localDateTime = this.converter.convert(now, LocalDateTime.class); - Date date = this.converter.convert(localDateTime, Date.class); - assertEquals(localDateTimeToMillis(localDateTime, ZoneId.systemDefault()), date.getTime()); - - // LocalDateTime to SqlDate - sqlDate = this.converter.convert(localDateTime, java.sql.Date.class); - assertEquals(localDateTimeToMillis(localDateTime, ZoneId.systemDefault()), sqlDate.getTime()); - - // LocalDateTime to Timestamp - timestamp = this.converter.convert(localDateTime, Timestamp.class); - assertEquals(localDateTimeToMillis(localDateTime, ZoneId.systemDefault()), timestamp.getTime()); - - // LocalDateTime to Long - long tnow = this.converter.convert(localDateTime, long.class); - assertEquals(localDateTimeToMillis(localDateTime, ZoneId.systemDefault()), tnow); - - // LocalDateTime to AtomicLong - atomicLong = this.converter.convert(localDateTime, AtomicLong.class); - assertEquals(localDateTimeToMillis(localDateTime, ZoneId.systemDefault()), atomicLong.get()); - - // LocalDateTime to String - strDate = this.converter.convert(localDateTime, String.class); - strDate2 = this.converter.convert(now, String.class); - assert strDate2.startsWith(strDate); - - // LocalDateTime to BigInteger - bigInt = this.converter.convert(localDateTime, BigInteger.class); - assertEquals(now.getTime(), bigInt.longValue()); - - // LocalDateTime to BigDecimal - bigDec = this.converter.convert(localDateTime, BigDecimal.class); - assertEquals(now.getTime(), bigDec.longValue()); + private static Stream identityParams() { + return Stream.of( + Arguments.of(9L, Long.class), + Arguments.of((short)10, Short.class), + Arguments.of("foo", String.class), + Arguments.of(LocalDate.now(), LocalDate.class), + Arguments.of(LocalDateTime.now(), LocalDateTime.class) + ); + } + @ParameterizedTest + @MethodSource("identityParams") + void testConversions_whenClassTypeMatchesObjectType_returnsItself(Object o, Class c) { + Object converted = this.converter.convert(o, c); + assertThat(converted).isSameAs(o); + } - // Error handling - try - { - this.converter.convert("2020-12-40", LocalDateTime.class); - fail(); - } - catch (IllegalArgumentException e) - { - TestUtil.assertContainsIgnoreCase(e.getMessage(), "day must be between 1 and 31"); - } + private static Stream nonIdentityParams() { + return Stream.of( + Arguments.of(new Date(), Date.class), + Arguments.of(new java.sql.Date(System.currentTimeMillis()), java.sql.Date.class), + Arguments.of(new Timestamp(System.currentTimeMillis()), Timestamp.class), + Arguments.of(Calendar.getInstance(), Calendar.class) + ); + } - assert this.converter.convert(null, LocalDateTime.class) == null; + @ParameterizedTest + @MethodSource("nonIdentityParams") + void testConversions_whenClassTypeMatchesObjectType_stillCreatesNewObject(Object o, Class c) { + Object converted = this.converter.convert(o, c); + assertThat(converted).isNotSameAs(o); } @Test - void testZonedDateTimeToOthers() + void testLocalDateTimeToOthers() { - // Date to ZonedDateTime - Calendar calendar = Calendar.getInstance(); - calendar.clear(); - calendar.set(2020, 8, 30, 13, 1, 11); - Date now = calendar.getTime(); - ZonedDateTime zonedDateTime = this.converter.convert(now, ZonedDateTime.class); - assertEquals(zonedDateTimeToMillis(zonedDateTime), now.getTime()); - - // ZonedDateTime to ZonedDateTime - identity check - ZonedDateTime x = this.converter.convert(zonedDateTime, ZonedDateTime.class); - assert zonedDateTime == x; - - // LocalDate to ZonedDateTime - LocalDate ld = LocalDate.of(2020, 8, 30); - x = this.converter.convert(ld, ZonedDateTime.class); - assert localDateToMillis(ld, ZoneId.systemDefault()) == zonedDateTimeToMillis(x); - - // LocalDateTime to ZonedDateTime - LocalDateTime ldt = LocalDateTime.of(2020, 8, 30, 13, 1, 11); - x = this.converter.convert(ldt, ZonedDateTime.class); - assert localDateTimeToMillis(ldt, ZoneId.systemDefault()) == zonedDateTimeToMillis(x); - - // ZonedDateTime to ZonedDateTime - ZonedDateTime zdt = ZonedDateTime.of(2020, 8, 30, 13, 1, 11, 0, ZoneId.systemDefault()); - x = this.converter.convert(zdt, ZonedDateTime.class); - assert zonedDateTimeToMillis(zdt) == zonedDateTimeToMillis(x); - - // Calendar to ZonedDateTime - x = this.converter.convert(calendar, ZonedDateTime.class); - assert zonedDateTimeToMillis(zonedDateTime) == calendar.getTime().getTime(); - - // SqlDate to ZonedDateTime - java.sql.Date sqlDate = this.converter.convert(now, java.sql.Date.class); - zonedDateTime = this.converter.convert(sqlDate, ZonedDateTime.class); - assertEquals(zonedDateTimeToMillis(zonedDateTime), localDateToMillis(sqlDate.toLocalDate(), ZoneId.systemDefault())); - - // Timestamp to ZonedDateTime - Timestamp timestamp = this.converter.convert(now, Timestamp.class); - zonedDateTime = this.converter.convert(timestamp, ZonedDateTime.class); - assertEquals(zonedDateTimeToMillis(zonedDateTime), timestamp.getTime()); - - // Long to ZonedDateTime - zonedDateTime = this.converter.convert(now.getTime(), ZonedDateTime.class); - assertEquals(zonedDateTimeToMillis(zonedDateTime), now.getTime()); - - // AtomicLong to ZonedDateTime - AtomicLong atomicLong = new AtomicLong(now.getTime()); - zonedDateTime = this.converter.convert(atomicLong, ZonedDateTime.class); - assertEquals(zonedDateTimeToMillis(zonedDateTime), now.getTime()); - - // String to ZonedDateTime - String strDate = this.converter.convert(now, String.class); - zonedDateTime = this.converter.convert(strDate, ZonedDateTime.class); - String strDate2 = this.converter.convert(zonedDateTime, String.class); - assert strDate2.startsWith(strDate); - - // BigInteger to ZonedDateTime - BigInteger bigInt = new BigInteger("" + now.getTime()); - zonedDateTime = this.converter.convert(bigInt, ZonedDateTime.class); - assertEquals(zonedDateTimeToMillis(zonedDateTime), now.getTime()); - - // BigDecimal to ZonedDateTime - BigDecimal bigDec = new BigDecimal(now.getTime()); - zonedDateTime = this.converter.convert(bigDec, ZonedDateTime.class); - assertEquals(zonedDateTimeToMillis(zonedDateTime), now.getTime()); - - // Other direction --> ZonedDateTime to other date types - - // ZonedDateTime to Date - zonedDateTime = this.converter.convert(now, ZonedDateTime.class); - Date date = this.converter.convert(zonedDateTime, Date.class); - assertEquals(zonedDateTimeToMillis(zonedDateTime), date.getTime()); - - // ZonedDateTime to SqlDate - sqlDate = this.converter.convert(zonedDateTime, java.sql.Date.class); - assertEquals(zonedDateTimeToMillis(zonedDateTime), sqlDate.getTime()); - - // ZonedDateTime to Timestamp - timestamp = this.converter.convert(zonedDateTime, Timestamp.class); - assertEquals(zonedDateTimeToMillis(zonedDateTime), timestamp.getTime()); - - // ZonedDateTime to Long - long tnow = this.converter.convert(zonedDateTime, long.class); - assertEquals(zonedDateTimeToMillis(zonedDateTime), tnow); - - // ZonedDateTime to AtomicLong - atomicLong = this.converter.convert(zonedDateTime, AtomicLong.class); - assertEquals(zonedDateTimeToMillis(zonedDateTime), atomicLong.get()); - - // ZonedDateTime to String - strDate = this.converter.convert(zonedDateTime, String.class); - strDate2 = this.converter.convert(now, String.class); - assert strDate.startsWith(strDate2); + // String to LocalDateTime +// String strDate = this.converter.convert(now, String.class); +// localDateTime = this.converter.convert(strDate, LocalDateTime.class); +// String strDate2 = this.converter.convert(localDateTime, String.class); +// assert strDate.startsWith(strDate2); +// +// // Other direction --> LocalDateTime to other date types +// +// // LocalDateTime to Date +// localDateTime = this.converter.convert(now, LocalDateTime.class); +// Date date = this.converter.convert(localDateTime, Date.class); +// assertEquals(localDateTimeToMillis(localDateTime), date.getTime()); +// +// // LocalDateTime to SqlDate +// sqlDate = this.converter.convert(localDateTime, java.sql.Date.class); +// assertEquals(localDateTimeToMillis(localDateTime), sqlDate.getTime()); +// +// // LocalDateTime to Timestamp +// timestamp = this.converter.convert(localDateTime, Timestamp.class); +// assertEquals(localDateTimeToMillis(localDateTime), timestamp.getTime()); +// +// // LocalDateTime to Long +// long tnow = this.converter.convert(localDateTime, long.class); +// assertEquals(localDateTimeToMillis(localDateTime), tnow); +// +// // LocalDateTime to AtomicLong +// atomicLong = this.converter.convert(localDateTime, AtomicLong.class); +// assertEquals(localDateTimeToMillis(localDateTime), atomicLong.get()); +// +// // LocalDateTime to String +// strDate = this.converter.convert(localDateTime, String.class); +// strDate2 = this.converter.convert(now, String.class); +// assert strDate2.startsWith(strDate); +// +// // LocalDateTime to BigInteger +// bigInt = this.converter.convert(localDateTime, BigInteger.class); +// assertEquals(now.getTime(), bigInt.longValue()); +// +// // LocalDateTime to BigDecimal +// bigDec = this.converter.convert(localDateTime, BigDecimal.class); +// assertEquals(now.getTime(), bigDec.longValue()); +// +// // Error handling +// try +// { +// this.converter.convert("2020-12-40", LocalDateTime.class); +// fail(); +// } +// catch (IllegalArgumentException e) +// { +// TestUtil.assertContainsIgnoreCase(e.getMessage(), "day must be between 1 and 31"); +// } +// +// assert this.converter.convert(null, LocalDateTime.class) == null; + } - // ZonedDateTime to BigInteger - bigInt = this.converter.convert(zonedDateTime, BigInteger.class); - assertEquals(now.getTime(), bigInt.longValue()); - // ZonedDateTime to BigDecimal - bigDec = this.converter.convert(zonedDateTime, BigDecimal.class); - assertEquals(now.getTime(), bigDec.longValue()); - - // Error handling - try { - this.converter.convert("2020-12-40", ZonedDateTime.class); - fail(); - } - catch (IllegalArgumentException e) { - TestUtil.assertContainsIgnoreCase(e.getMessage(), "day must be between 1 and 31"); - } - - assert this.converter.convert(null, ZonedDateTime.class) == null; - } @Test void testDateErrorHandlingBadInput() @@ -1761,6 +2157,52 @@ void testFloat() } } + + private static Stream testDoubleParams() { + return Stream.of( + Arguments.of("-32768", -32768), + Arguments.of("-45000", -45000), + Arguments.of("32767", 32767), + Arguments.of(new BigInteger("8675309"), 8675309), + Arguments.of(Byte.MIN_VALUE,-128), + Arguments.of(Byte.MAX_VALUE, 127), + Arguments.of(Short.MIN_VALUE, -32768), + Arguments.of(Short.MAX_VALUE, 32767), + Arguments.of(Integer.MIN_VALUE, Integer.MIN_VALUE), + Arguments.of(Integer.MAX_VALUE, Integer.MAX_VALUE), + Arguments.of(-128L, -128d), + Arguments.of(127L, 127d), + Arguments.of(3.14, 3.14d), + Arguments.of(3.14159d, 3.14159d), + Arguments.of(-128.0f, -128d), + Arguments.of(127.0f, 127d), + Arguments.of(-128.0d, -128d), + Arguments.of(127.0d, 127d), + Arguments.of( new BigDecimal("100"),100), + Arguments.of( new BigInteger("120"), 120), + Arguments.of( new AtomicInteger(75), 75), + Arguments.of( new AtomicInteger(1), 1), + Arguments.of( new AtomicInteger(0), 0), + Arguments.of( new AtomicLong(Integer.MAX_VALUE), Integer.MAX_VALUE) + ); + } + + @ParameterizedTest + @MethodSource("testDoubleParams") + void testDouble(Object value, double expectedResult) + { + double converted = this.converter.convert(value, double.class); + assertThat(converted).isEqualTo(expectedResult); + } + + @ParameterizedTest + @MethodSource("testDoubleParams") + void testDouble_ObjectType(Object value, double expectedResult) + { + Double converted = this.converter.convert(value, Double.class); + assertThat(converted).isEqualTo(Double.valueOf(expectedResult)); + } + @Test void testDouble() { @@ -1804,6 +2246,10 @@ void testDouble() @Test void testBoolean() { + /** + * + * assertEquals(converter.convert(new BigInteger("314159"), Boolean.class), true); + */ assertEquals(true, this.converter.convert(-3.14d, boolean.class)); assertEquals(false, this.converter.convert(0.0d, boolean.class)); assertEquals(true, this.converter.convert(-3.14f, Boolean.class)); @@ -2023,6 +2469,7 @@ void testMapToGregCalendar() @Test void testMapToDate() { + long now = System.currentTimeMillis(); final Map map = new HashMap(); map.put("value", now); @@ -2063,7 +2510,7 @@ void testMapToSqlDate() map.clear(); assertThatThrownBy(() -> this.converter.convert(map, java.sql.Date.class)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("the map must include keys: [time], or '_v' or 'value'"); + .hasMessageContaining("map must include keys"); } @Test @@ -2093,9 +2540,8 @@ void testMapToTimestamp() void testMapToLocalDate() { LocalDate today = LocalDate.now(); - long now = today.toEpochDay(); final Map map = new HashMap(); - map.put("value", now); + map.put("value", today); LocalDate date = this.converter.convert(map, LocalDate.class); assert date.equals(today); @@ -2170,79 +2616,75 @@ void testUnsupportedType() } } + + + private static Stream classesThatReturnNull_whenConvertingFromNull() { + return Stream.of( + Arguments.of(Class.class), + Arguments.of(String.class), + Arguments.of(AtomicLong.class), + Arguments.of(AtomicInteger.class), + Arguments.of(AtomicBoolean.class), + Arguments.of(BigDecimal.class), + Arguments.of(BigInteger.class), + Arguments.of(Timestamp.class), + Arguments.of(java.sql.Date.class), + Arguments.of(Date.class), + Arguments.of(Character.class), + Arguments.of(Double.class), + Arguments.of(Float.class), + Arguments.of(Long.class), + Arguments.of(Short.class), + Arguments.of(Integer.class), + Arguments.of(Byte.class), + Arguments.of(Boolean.class), + Arguments.of(Byte.class) + ); + } + + @ParameterizedTest + @MethodSource("classesThatReturnNull_whenConvertingFromNull") + void testClassesThatReturnNull_whenConvertingFromNull(Class c) + { + assertThat(this.converter.convert(null, c)).isNull(); + } + + private static Stream classesThatReturnZero_whenConvertingFromNull() { + return Stream.of( + Arguments.of(byte.class, (byte)0), + Arguments.of(int.class, 0), + Arguments.of(short.class, (short)0), + Arguments.of(char.class, (char)0), + Arguments.of(long.class, 0L), + Arguments.of(float.class, 0.0f), + Arguments.of(double.class, 0.0d) + ); + } + + @ParameterizedTest + @MethodSource("classesThatReturnZero_whenConvertingFromNull") + void testClassesThatReturnZero_whenConvertingFromNull(Class c, Object expected) + { + Object zero = this.converter.convert(null, c); + assertThat(zero).isEqualTo(expected); + } + + private static Stream classesThatReturnFalse_whenConvertingFromNull() { + return Stream.of( + Arguments.of(Boolean.class), + Arguments.of(boolean.class) + ); + } + @Test - void testNullInstance() - { - assert 0L == this.converter.convert(null, long.class); - assert !this.converter.convert(null, boolean.class); - assert null == this.converter.convert(null, Boolean.class); - assert 0 == this.converter.convert(null, byte.class); - assert null == this.converter.convert(null, Byte.class); - assert 0 == this.converter.convert(null, short.class); - assert null == this.converter.convert(null, Short.class); - assert 0 == this.converter.convert(null, int.class); - assert null == this.converter.convert(null, Integer.class); - assert null == this.converter.convert(null, Long.class); - assert 0.0f == this.converter.convert(null, float.class); - assert null == this.converter.convert(null, Float.class); - assert 0.0d == this.converter.convert(null, double.class); - assert null == this.converter.convert(null, Double.class); - assert (char) 0 == this.converter.convert(null, char.class); - assert null == this.converter.convert(null, Character.class); - - assert null == this.converter.convert(null, Date.class); - assert null == this.converter.convert(null, java.sql.Date.class); - assert null == this.converter.convert(null, Timestamp.class); - assert null == this.converter.convert(null, Calendar.class); - assert null == this.converter.convert(null, String.class); - assert null == this.converter.convert(null, BigInteger.class); - assert null == this.converter.convert(null, BigDecimal.class); - assert null == this.converter.convert(null, AtomicBoolean.class); - assert null == this.converter.convert(null, AtomicInteger.class); - assert null == this.converter.convert(null, AtomicLong.class); - - assert null == this.converter.convert(null, Byte.class); - assert null == this.converter.convert(null, Integer.class); - assert null == this.converter.convert(null, Short.class); - assert null == this.converter.convert(null, Long.class); - assert null == this.converter.convert(null, Float.class); - assert null == this.converter.convert(null, Double.class); - assert null == this.converter.convert(null, Character.class); - assert null == this.converter.convert(null, Date.class); - assert null == this.converter.convert(null, java.sql.Date.class); - assert null == this.converter.convert(null, Timestamp.class); - assert null == this.converter.convert(null, AtomicBoolean.class); - assert null == this.converter.convert(null, AtomicInteger.class); - assert null == this.converter.convert(null, AtomicLong.class); - assert null == this.converter.convert(null, String.class); - - assert false == this.converter.convert(null, boolean.class); - assert 0 == this.converter.convert(null, byte.class); - assert 0 == this.converter.convert(null, int.class); - assert 0 == this.converter.convert(null, short.class); - assert 0 == this.converter.convert(null, long.class); - assert 0.0f == this.converter.convert(null, float.class); - assert 0.0d == this.converter.convert(null, double.class); - assert (char) 0 == this.converter.convert(null, char.class); - assert null == this.converter.convert(null, BigInteger.class); - assert null == this.converter.convert(null, BigDecimal.class); - assert null == this.converter.convert(null, AtomicBoolean.class); - assert null == this.converter.convert(null, AtomicInteger.class); - assert null == this.converter.convert(null, AtomicLong.class); - assert null == this.converter.convert(null, String.class); + void testConvertFromNullToBoolean() { + boolean b = this.converter.convert(null, boolean.class); + assertThat(b).isFalse(); } @Test void testConvert2() { - assert !this.converter.convert(null, boolean.class); - assert this.converter.convert("true", boolean.class); - assert this.converter.convert("true", Boolean.class); - assert !this.converter.convert("false", boolean.class); - assert !this.converter.convert("false", Boolean.class); - assert !this.converter.convert("", boolean.class); - assert !this.converter.convert("", Boolean.class); - assert null == this.converter.convert(null, Boolean.class); assert -8 == this.converter.convert("-8", byte.class); assert -8 == this.converter.convert("-8", int.class); assert -8 == this.converter.convert("-8", short.class); @@ -2259,30 +2701,14 @@ void testConvert2() } @Test - void testNullType() + void whenClassToConvertToIsNull_throwsException() { assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> this.converter.convert("123", null)) // 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"); } - @Test - void testEmptyString() - { - assertEquals(false, this.converter.convert("", boolean.class)); - assertEquals(false, this.converter.convert("", boolean.class)); - assert (byte) 0 == this.converter.convert("", byte.class); - assert (short) 0 == this.converter.convert("", short.class); - assert 0 == this.converter.convert("", int.class); - assert (long) 0 == this.converter.convert("", long.class); - assert 0.0f == this.converter.convert("", float.class); - assert 0.0d == this.converter.convert("", double.class); - assertEquals(BigDecimal.ZERO, this.converter.convert("", BigDecimal.class)); - assertEquals(BigInteger.ZERO, this.converter.convert("", BigInteger.class)); - assertEquals(false, this.converter.convert("", AtomicBoolean.class).get()); - assertEquals(0, this.converter.convert("", AtomicInteger.class).get()); - assertEquals(0L, this.converter.convert("", AtomicLong.class).get()); - } + @Test void testEnumSupport() @@ -2354,45 +2780,6 @@ void testLongToBigDecimal() assert big == null; } - @Test - void testLocalDate() - { - Calendar cal = Calendar.getInstance(); - cal.clear(); - cal.set(2020, 8, 4); // 0-based for month - - BigDecimal big = this.converter.convert(LocalDate.of(2020, 9, 4), BigDecimal.class); - LocalDate out = LocalDate.ofEpochDay(big.longValue()); - assert out.getYear() == 2020; - assert out.getMonthValue() == 9; - assert out.getDayOfMonth() == 4; - - BigInteger bigI = this.converter.convert(LocalDate.of(2020, 9, 4), BigInteger.class); - out = LocalDate.ofEpochDay(bigI.longValue()); - assert out.getYear() == 2020; - assert out.getMonthValue() == 9; - assert out.getDayOfMonth() == 4; - - java.sql.Date sqlDate = this.converter.convert(LocalDate.of(2020, 9, 4), java.sql.Date.class); - assert sqlDate.getTime() == cal.getTime().getTime(); - - Timestamp timestamp = this.converter.convert(LocalDate.of(2020, 9, 4), Timestamp.class); - assert timestamp.getTime() == cal.getTime().getTime(); - - Date date = this.converter.convert(LocalDate.of(2020, 9, 4), Date.class); - assert date.getTime() == cal.getTime().getTime(); - - LocalDate particular = LocalDate.of(2020, 9, 4); - Long lng = this.converter.convert(LocalDate.of(2020, 9, 4), Long.class); - LocalDate xyz = LocalDate.ofEpochDay(lng); - assertEquals(xyz, particular); - - AtomicLong atomicLong = this.converter.convert(LocalDate.of(2020, 9, 4), AtomicLong.class); - out = LocalDate.ofEpochDay(atomicLong.longValue()); - assert out.getYear() == 2020; - assert out.getMonthValue() == 9; - assert out.getDayOfMonth() == 4; - } @Test void testLocalDateTimeToBig() @@ -2446,18 +2833,32 @@ void testLocalZonedDateTimeToBig() assert atomicLong.get() == cal.getTime().getTime(); } - @Test - void testStringToClass() + + private static Stream stringToClassParams() { + return Stream.of( + Arguments.of("java.math.BigInteger"), + Arguments.of("java.lang.String") + ); + } + @ParameterizedTest + @MethodSource("stringToClassParams") + void stringToClass(String className) { - Class clazz = this.converter.convert("java.math.BigInteger", Class.class); - assert clazz.getName().equals("java.math.BigInteger"); + Class c = this.converter.convert(className, Class.class); + assertThat(c).isNotNull(); + assertThat(c.getName()).isEqualTo(className); + } + + @Test + void stringToClass_whenNotFound_throwsException() { assertThatThrownBy(() -> this.converter.convert("foo.bar.baz.Qux", Class.class)) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("Cannot convert String 'foo.bar.baz.Qux' to class. Class not found"); + } - assertNull(this.converter.convert(null, Class.class)); - + @Test + void stringToClass_whenUnsupportedConversion_throwsException() { assertThatThrownBy(() -> this.converter.convert(16.0, Class.class)) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("Unsupported conversion, source type [Double (16.0)] target type 'Class'"); @@ -3210,7 +3611,12 @@ private static Stream emptyStringToType_params() { Arguments.of("", float.class, 0.0f), Arguments.of("", Float.class, 0.0f), Arguments.of("", double.class, 0.0d), - Arguments.of("", Double.class, 0.0d)); + Arguments.of("", Double.class, 0.0d), + Arguments.of("", Boolean.class, false), + Arguments.of("", boolean.class, false), + Arguments.of("", BigDecimal.class, BigDecimal.ZERO), + Arguments.of("", BigInteger.class, BigInteger.ZERO) + ); } @ParameterizedTest @@ -3220,4 +3626,47 @@ void emptyStringToType(Object value, Class type, Object expected) Object converted = this.converter.convert(value, type); assertThat(converted).isEqualTo(expected); } + + @Test + void emptyStringToAtomicBoolean() + { + AtomicBoolean converted = this.converter.convert("", AtomicBoolean.class); + assertThat(converted.get()).isEqualTo(false); + } + + @Test + void emptyStringToAtomicInteger() + { + AtomicInteger converted = this.converter.convert("", AtomicInteger.class); + assertThat(converted.get()).isEqualTo(0); + } + + @Test + void emptyStringToAtomicLong() + { + AtomicLong converted = this.converter.convert("", AtomicLong.class); + assertThat(converted.get()).isEqualTo(0); + } + + private ConverterOptions createConvertOptions(ZoneId sourceZoneId, final ZoneId targetZoneId) + { + return new ConverterOptions() { + @Override + public T getCustomOption(String name) { + return null; + } + + @Override + public ZoneId getZoneId() { + return targetZoneId; + } + + @Override + public ZoneId getSourceZoneIdForLocalDates() { + return sourceZoneId; + } + }; + } + + private ConverterOptions chicagoZone() { return createConvertOptions(null, CHICAGO); } } diff --git a/src/test/java/com/cedarsoftware/util/convert/DateConversionTests.java b/src/test/java/com/cedarsoftware/util/convert/DateConversionTests.java new file mode 100644 index 00000000..e8b3c678 --- /dev/null +++ b/src/test/java/com/cedarsoftware/util/convert/DateConversionTests.java @@ -0,0 +1,19 @@ +package com.cedarsoftware.util.convert; + +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; + +public class DateConversionTests { + public void testDateToCalendarTimeZone() { + Date date = new Date(); + + System.out.println(date); + + TimeZone timeZone = TimeZone.getTimeZone("America/New_York"); + Calendar cal = Calendar.getInstance(timeZone); + cal.setTime(date); + + System.out.println(date); + } +}