diff --git a/src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversions.java b/src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversions.java index 1794ae67..6de33ba2 100644 --- a/src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversions.java +++ b/src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversions.java @@ -72,7 +72,6 @@ static AtomicInteger toAtomicInteger(Object from, Converter converter) { return b.get() ? new AtomicInteger(1) : new AtomicInteger (0); } - static AtomicLong toAtomicLong(Object from, Converter converter) { AtomicBoolean b = (AtomicBoolean) from; return b.get() ? new AtomicLong(1) : new AtomicLong(0); diff --git a/src/main/java/com/cedarsoftware/util/convert/AtomicIntegerConversions.java b/src/main/java/com/cedarsoftware/util/convert/AtomicIntegerConversions.java new file mode 100644 index 00000000..d7ce28b2 --- /dev/null +++ b/src/main/java/com/cedarsoftware/util/convert/AtomicIntegerConversions.java @@ -0,0 +1,36 @@ +package com.cedarsoftware.util.convert; + +import java.time.LocalTime; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author John DeRegnaucourt (jdereg@gmail.com) + *
+ * Copyright (c) Cedar Software LLC + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * License + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +final class AtomicIntegerConversions { + + private AtomicIntegerConversions() {} + + static AtomicInteger toAtomicInteger(Object from, Converter converter) { + AtomicInteger atomicInt = (AtomicInteger) from; + return new AtomicInteger(atomicInt.intValue()); + } + + static LocalTime toLocalTime(Object from, Converter converter) { + AtomicInteger atomicInteger= (AtomicInteger) from; + return LongConversions.toLocalTime((long)atomicInteger.get(), converter); + } +} diff --git a/src/main/java/com/cedarsoftware/util/convert/AtomicLongConversions.java b/src/main/java/com/cedarsoftware/util/convert/AtomicLongConversions.java new file mode 100644 index 00000000..76b6c6d4 --- /dev/null +++ b/src/main/java/com/cedarsoftware/util/convert/AtomicLongConversions.java @@ -0,0 +1,36 @@ +package com.cedarsoftware.util.convert; + +import java.time.LocalTime; +import java.util.concurrent.atomic.AtomicLong; + +/** + * @author John DeRegnaucourt (jdereg@gmail.com) + *
+ * Copyright (c) Cedar Software LLC + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * License + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +final class AtomicLongConversions { + + private AtomicLongConversions() {} + + static AtomicLong toAtomicLong(Object from, Converter converter) { + AtomicLong atomicLong = (AtomicLong) from; + return new AtomicLong(atomicLong.get()); + } + + static LocalTime toLocalTime(Object from, Converter converter) { + AtomicLong atomicLong = (AtomicLong) from; + return LongConversions.toLocalTime(atomicLong.get(), converter); + } +} diff --git a/src/main/java/com/cedarsoftware/util/convert/BigDecimalConversions.java b/src/main/java/com/cedarsoftware/util/convert/BigDecimalConversions.java index ace157dc..c54375c0 100644 --- a/src/main/java/com/cedarsoftware/util/convert/BigDecimalConversions.java +++ b/src/main/java/com/cedarsoftware/util/convert/BigDecimalConversions.java @@ -7,6 +7,7 @@ import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.OffsetDateTime; import java.time.ZonedDateTime; import java.util.Date; @@ -46,6 +47,17 @@ static Duration toDuration(Object from, Converter converter) { return Duration.ofSeconds(seconds.longValue(), nanos.movePointRight(9).longValue()); } + static LocalTime toLocalTime(Object from, Converter converter) { + BigDecimal seconds = (BigDecimal) from; + BigDecimal nanos = seconds.multiply(BigDecimal.valueOf(1_000_000_000)); + try { + return LocalTime.ofNanoOfDay(nanos.longValue()); + } + catch (Exception e) { + throw new IllegalArgumentException("Input value [" + seconds.toPlainString() + "] for conversion to LocalTime must be >= 0 && <= 86399.999999999", e); + } + } + static LocalDate toLocalDate(Object from, Converter converter) { return toZonedDateTime(from, converter).toLocalDate(); } diff --git a/src/main/java/com/cedarsoftware/util/convert/BigIntegerConversions.java b/src/main/java/com/cedarsoftware/util/convert/BigIntegerConversions.java index 7a05fd47..fec623fb 100644 --- a/src/main/java/com/cedarsoftware/util/convert/BigIntegerConversions.java +++ b/src/main/java/com/cedarsoftware/util/convert/BigIntegerConversions.java @@ -7,6 +7,7 @@ import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.OffsetDateTime; import java.time.ZonedDateTime; import java.util.Date; @@ -81,6 +82,15 @@ static ZonedDateTime toZonedDateTime(Object from, Converter converter) { return toInstant(from, converter).atZone(converter.getOptions().getZoneId()); } + static LocalTime toLocalTime(Object from, Converter converter) { + BigInteger bigI = (BigInteger) from; + try { + return LocalTime.ofNanoOfDay(bigI.longValue()); + } catch (Exception e) { + throw new IllegalArgumentException("Input value [" + bigI + "] for conversion to LocalTime must be >= 0 && <= 86399999999999", e); + } + } + static LocalDate toLocalDate(Object from, Converter converter) { return toZonedDateTime(from, converter).toLocalDate(); } diff --git a/src/main/java/com/cedarsoftware/util/convert/Converter.java b/src/main/java/com/cedarsoftware/util/convert/Converter.java index bb23773b..7e5911c2 100644 --- a/src/main/java/com/cedarsoftware/util/convert/Converter.java +++ b/src/main/java/com/cedarsoftware/util/convert/Converter.java @@ -160,6 +160,7 @@ private static void buildFactoryConversions() { CONVERSION_DB.put(pair(Number.class, Integer.class), NumberConversions::toInt); CONVERSION_DB.put(pair(Map.class, Integer.class), MapConversions::toInt); CONVERSION_DB.put(pair(String.class, Integer.class), StringConversions::toInt); + CONVERSION_DB.put(pair(LocalTime.class, Integer.class), LocalTimeConversions::toInteger); CONVERSION_DB.put(pair(Year.class, Integer.class), YearConversions::toInt); // toLong @@ -184,6 +185,7 @@ private static void buildFactoryConversions() { CONVERSION_DB.put(pair(Instant.class, Long.class), InstantConversions::toLong); CONVERSION_DB.put(pair(Duration.class, Long.class), DurationConversions::toLong); CONVERSION_DB.put(pair(LocalDate.class, Long.class), LocalDateConversions::toLong); + CONVERSION_DB.put(pair(LocalTime.class, Long.class), LocalTimeConversions::toLong); CONVERSION_DB.put(pair(LocalDateTime.class, Long.class), LocalDateTimeConversions::toLong); CONVERSION_DB.put(pair(OffsetDateTime.class, Long.class), OffsetDateTimeConversions::toLong); CONVERSION_DB.put(pair(ZonedDateTime.class, Long.class), ZonedDateTimeConversions::toLong); @@ -227,6 +229,7 @@ private static void buildFactoryConversions() { CONVERSION_DB.put(pair(Character.class, Double.class), CharacterConversions::toDouble); CONVERSION_DB.put(pair(Duration.class, Double.class), DurationConversions::toDouble); CONVERSION_DB.put(pair(Instant.class, Double.class), InstantConversions::toDouble); + CONVERSION_DB.put(pair(LocalTime.class, Double.class), LocalTimeConversions::toDouble); CONVERSION_DB.put(pair(LocalDate.class, Double.class), LocalDateConversions::toDouble); CONVERSION_DB.put(pair(LocalDateTime.class, Double.class), LocalDateTimeConversions::toDouble); CONVERSION_DB.put(pair(ZonedDateTime.class, Double.class), ZonedDateTimeConversions::toDouble); @@ -305,6 +308,7 @@ private static void buildFactoryConversions() { CONVERSION_DB.put(pair(Timestamp.class, BigInteger.class), TimestampConversions::toBigInteger); CONVERSION_DB.put(pair(Duration.class, BigInteger.class), DurationConversions::toBigInteger); CONVERSION_DB.put(pair(Instant.class, BigInteger.class), InstantConversions::toBigInteger); + CONVERSION_DB.put(pair(LocalTime.class, BigInteger.class), LocalTimeConversions::toBigInteger); CONVERSION_DB.put(pair(LocalDate.class, BigInteger.class), LocalDateConversions::toBigInteger); CONVERSION_DB.put(pair(LocalDateTime.class, BigInteger.class), LocalDateTimeConversions::toBigInteger); CONVERSION_DB.put(pair(ZonedDateTime.class, BigInteger.class), ZonedDateTimeConversions::toBigInteger); @@ -336,6 +340,7 @@ private static void buildFactoryConversions() { CONVERSION_DB.put(pair(Timestamp.class, BigDecimal.class), TimestampConversions::toBigDecimal); CONVERSION_DB.put(pair(Instant.class, BigDecimal.class), InstantConversions::toBigDecimal); CONVERSION_DB.put(pair(Duration.class, BigDecimal.class), DurationConversions::toBigDecimal); + CONVERSION_DB.put(pair(LocalTime.class, BigDecimal.class), LocalTimeConversions::toBigDecimal); CONVERSION_DB.put(pair(LocalDate.class, BigDecimal.class), LocalDateConversions::toBigDecimal); CONVERSION_DB.put(pair(LocalDateTime.class, BigDecimal.class), LocalDateTimeConversions::toBigDecimal); CONVERSION_DB.put(pair(ZonedDateTime.class, BigDecimal.class), ZonedDateTimeConversions::toBigDecimal); @@ -379,9 +384,10 @@ private static void buildFactoryConversions() { CONVERSION_DB.put(pair(Character.class, AtomicInteger.class), CharacterConversions::toAtomicInteger); CONVERSION_DB.put(pair(BigInteger.class, AtomicInteger.class), NumberConversions::toAtomicInteger); CONVERSION_DB.put(pair(BigDecimal.class, AtomicInteger.class), NumberConversions::toAtomicInteger); - CONVERSION_DB.put(pair(AtomicInteger.class, AtomicInteger.class), NumberConversions::toAtomicInteger); + CONVERSION_DB.put(pair(AtomicInteger.class, AtomicInteger.class), AtomicIntegerConversions::toAtomicInteger); CONVERSION_DB.put(pair(AtomicBoolean.class, AtomicInteger.class), AtomicBooleanConversions::toAtomicInteger); CONVERSION_DB.put(pair(AtomicLong.class, AtomicInteger.class), NumberConversions::toAtomicInteger); + CONVERSION_DB.put(pair(LocalTime.class, AtomicInteger.class), LocalTimeConversions::toAtomicInteger); CONVERSION_DB.put(pair(LocalDate.class, AtomicInteger.class), LocalDateConversions::toAtomicLong); CONVERSION_DB.put(pair(Number.class, AtomicBoolean.class), NumberConversions::toAtomicInteger); CONVERSION_DB.put(pair(Map.class, AtomicInteger.class), MapConversions::toAtomicInteger); @@ -401,14 +407,15 @@ private static void buildFactoryConversions() { CONVERSION_DB.put(pair(BigInteger.class, AtomicLong.class), NumberConversions::toAtomicLong); CONVERSION_DB.put(pair(BigDecimal.class, AtomicLong.class), NumberConversions::toAtomicLong); CONVERSION_DB.put(pair(AtomicBoolean.class, AtomicLong.class), AtomicBooleanConversions::toAtomicLong); - CONVERSION_DB.put(pair(AtomicLong.class, AtomicLong.class), Converter::identity); CONVERSION_DB.put(pair(AtomicInteger.class, AtomicLong.class), NumberConversions::toAtomicLong); + CONVERSION_DB.put(pair(AtomicLong.class, AtomicLong.class), AtomicLongConversions::toAtomicLong); CONVERSION_DB.put(pair(Date.class, AtomicLong.class), DateConversions::toAtomicLong); CONVERSION_DB.put(pair(java.sql.Date.class, AtomicLong.class), DateConversions::toAtomicLong); CONVERSION_DB.put(pair(Timestamp.class, AtomicLong.class), DateConversions::toAtomicLong); CONVERSION_DB.put(pair(Instant.class, AtomicLong.class), InstantConversions::toAtomicLong); CONVERSION_DB.put(pair(Duration.class, AtomicLong.class), DurationConversions::toAtomicLong); CONVERSION_DB.put(pair(LocalDate.class, AtomicLong.class), LocalDateConversions::toAtomicLong); + CONVERSION_DB.put(pair(LocalTime.class, AtomicLong.class), LocalTimeConversions::toAtomicLong); CONVERSION_DB.put(pair(LocalDateTime.class, AtomicLong.class), LocalDateTimeConversions::toAtomicLong); CONVERSION_DB.put(pair(ZonedDateTime.class, AtomicLong.class), ZonedDateTimeConversions::toAtomicLong); CONVERSION_DB.put(pair(OffsetDateTime.class, AtomicLong.class), OffsetDateTimeConversions::toAtomicLong); @@ -567,13 +574,13 @@ private static void buildFactoryConversions() { CONVERSION_DB.put(pair(Void.class, LocalTime.class), VoidConversions::toNull); CONVERSION_DB.put(pair(Byte.class, LocalTime.class), UNSUPPORTED); CONVERSION_DB.put(pair(Short.class, LocalTime.class), UNSUPPORTED); - CONVERSION_DB.put(pair(Integer.class, LocalTime.class), UNSUPPORTED); - CONVERSION_DB.put(pair(Long.class, LocalTime.class), NumberConversions::toLocalTime); - CONVERSION_DB.put(pair(Double.class, LocalTime.class), NumberConversions::toLocalTime); - CONVERSION_DB.put(pair(BigInteger.class, LocalTime.class), NumberConversions::toLocalTime); - CONVERSION_DB.put(pair(BigDecimal.class, LocalTime.class), NumberConversions::toLocalDateTime); - CONVERSION_DB.put(pair(AtomicInteger.class, LocalTime.class), UNSUPPORTED); - CONVERSION_DB.put(pair(AtomicLong.class, LocalTime.class), NumberConversions::toLocalTime); + CONVERSION_DB.put(pair(Integer.class, LocalTime.class), IntegerConversions::toLocalTime); + CONVERSION_DB.put(pair(Long.class, LocalTime.class), LongConversions::toLocalTime); + CONVERSION_DB.put(pair(Double.class, LocalTime.class), DoubleConversions::toLocalTime); + CONVERSION_DB.put(pair(BigInteger.class, LocalTime.class), BigIntegerConversions::toLocalTime); + CONVERSION_DB.put(pair(BigDecimal.class, LocalTime.class), BigDecimalConversions::toLocalTime); + CONVERSION_DB.put(pair(AtomicInteger.class, LocalTime.class), AtomicIntegerConversions::toLocalTime); + CONVERSION_DB.put(pair(AtomicLong.class, LocalTime.class), AtomicLongConversions::toLocalTime); CONVERSION_DB.put(pair(java.sql.Date.class, LocalTime.class), DateConversions::toLocalTime); CONVERSION_DB.put(pair(Timestamp.class, LocalTime.class), DateConversions::toLocalTime); CONVERSION_DB.put(pair(Date.class, LocalTime.class), DateConversions::toLocalTime); @@ -584,7 +591,6 @@ private static void buildFactoryConversions() { CONVERSION_DB.put(pair(ZonedDateTime.class, LocalTime.class), ZonedDateTimeConversions::toLocalTime); CONVERSION_DB.put(pair(OffsetDateTime.class, LocalTime.class), OffsetDateTimeConversions::toLocalTime); CONVERSION_DB.put(pair(Calendar.class, LocalTime.class), CalendarConversions::toLocalTime); - CONVERSION_DB.put(pair(Number.class, LocalTime.class), NumberConversions::toLocalTime); CONVERSION_DB.put(pair(Map.class, LocalTime.class), MapConversions::toLocalTime); CONVERSION_DB.put(pair(String.class, LocalTime.class), StringConversions::toLocalTime); diff --git a/src/main/java/com/cedarsoftware/util/convert/DoubleConversions.java b/src/main/java/com/cedarsoftware/util/convert/DoubleConversions.java index b4053b46..baf20507 100644 --- a/src/main/java/com/cedarsoftware/util/convert/DoubleConversions.java +++ b/src/main/java/com/cedarsoftware/util/convert/DoubleConversions.java @@ -5,6 +5,7 @@ import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.OffsetDateTime; import java.time.ZonedDateTime; import java.util.Date; @@ -46,6 +47,17 @@ static Date toSqlDate(Object from, Converter converter) { return new java.sql.Date((long)(d * 1000)); } + static LocalTime toLocalTime(Object from, Converter converter) { + double seconds = (double) from; + double nanos = seconds * 1_000_000_000.0; + try { + return LocalTime.ofNanoOfDay((long)nanos); + } + catch (Exception e) { + throw new IllegalArgumentException("Input value [" + seconds + "] for conversion to LocalTime must be >= 0 && <= 86399.999999999", e); + } + } + static LocalDate toLocalDate(Object from, Converter converter) { return toZonedDateTime(from, converter).toLocalDate(); } diff --git a/src/main/java/com/cedarsoftware/util/convert/IntegerConversions.java b/src/main/java/com/cedarsoftware/util/convert/IntegerConversions.java new file mode 100644 index 00000000..600a476e --- /dev/null +++ b/src/main/java/com/cedarsoftware/util/convert/IntegerConversions.java @@ -0,0 +1,30 @@ +package com.cedarsoftware.util.convert; + +import java.time.LocalTime; + +/** + * @author John DeRegnaucourt (jdereg@gmail.com) + *
+ * Copyright (c) Cedar Software LLC + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * License + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +final class IntegerConversions { + + private IntegerConversions() {} + + static LocalTime toLocalTime(Object from, Converter converter) { + int ms = (Integer) from; + return LongConversions.toLocalTime((long)ms, converter); + } +} diff --git a/src/main/java/com/cedarsoftware/util/convert/LocalTimeConversions.java b/src/main/java/com/cedarsoftware/util/convert/LocalTimeConversions.java index c3c6dc3a..68c27dae 100644 --- a/src/main/java/com/cedarsoftware/util/convert/LocalTimeConversions.java +++ b/src/main/java/com/cedarsoftware/util/convert/LocalTimeConversions.java @@ -1,8 +1,13 @@ package com.cedarsoftware.util.convert; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.RoundingMode; import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import com.cedarsoftware.util.CompactLinkedMap; @@ -24,6 +29,7 @@ * limitations under the License. */ final class LocalTimeConversions { + static final BigDecimal BILLION = BigDecimal.valueOf(1_000_000_000); private LocalTimeConversions() {} @@ -43,6 +49,39 @@ static Map toMap(Object from, Converter converter) { return target; } + static int toInteger(Object from, Converter converter) { + LocalTime lt = (LocalTime) from; + return (int) (lt.toNanoOfDay() / 1_000_000); // Convert nanoseconds to milliseconds. + } + + static long toLong(Object from, Converter converter) { + LocalTime lt = (LocalTime) from; + return lt.toNanoOfDay() / 1_000_000; // Convert nanoseconds to milliseconds. + } + + static double toDouble(Object from, Converter converter) { + LocalTime lt = (LocalTime) from; + return lt.toNanoOfDay() / 1_000_000_000.0; + } + + static BigInteger toBigInteger(Object from, Converter converter) { + LocalTime lt = (LocalTime) from; + return BigInteger.valueOf(lt.toNanoOfDay()); + } + + static BigDecimal toBigDecimal(Object from, Converter converter) { + LocalTime lt = (LocalTime) from; + return new BigDecimal(lt.toNanoOfDay()).divide(BILLION, 9, RoundingMode.HALF_UP); + } + + static AtomicInteger toAtomicInteger(Object from, Converter converter) { + return new AtomicInteger((int)toLong(from, converter)); + } + + static AtomicLong toAtomicLong(Object from, Converter converter) { + return new AtomicLong(toLong(from, converter)); + } + static String toString(Object from, Converter converter) { LocalTime localTime = (LocalTime) from; return localTime.format(DateTimeFormatter.ISO_LOCAL_TIME); diff --git a/src/main/java/com/cedarsoftware/util/convert/LongConversions.java b/src/main/java/com/cedarsoftware/util/convert/LongConversions.java new file mode 100644 index 00000000..3dfdd545 --- /dev/null +++ b/src/main/java/com/cedarsoftware/util/convert/LongConversions.java @@ -0,0 +1,34 @@ +package com.cedarsoftware.util.convert; + +import java.time.LocalTime; + +/** + * @author John DeRegnaucourt (jdereg@gmail.com) + *
+ * Copyright (c) Cedar Software LLC + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * License + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +final class LongConversions { + + private LongConversions() {} + + static LocalTime toLocalTime(Object from, Converter converter) { + long millis = (Long) from; + try { + return LocalTime.ofNanoOfDay(millis * 1_000_000); + } catch (Exception e) { + throw new IllegalArgumentException("Input value [" + millis + "] for conversion to LocalTime must be >= 0 && <= 86399999", e); + } + } +} diff --git a/src/main/java/com/cedarsoftware/util/convert/NumberConversions.java b/src/main/java/com/cedarsoftware/util/convert/NumberConversions.java index 6ab697a7..d2e447ed 100644 --- a/src/main/java/com/cedarsoftware/util/convert/NumberConversions.java +++ b/src/main/java/com/cedarsoftware/util/convert/NumberConversions.java @@ -7,7 +7,6 @@ import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.LocalTime; import java.time.OffsetDateTime; import java.time.Year; import java.time.ZonedDateTime; @@ -203,11 +202,7 @@ static LocalDate toLocalDate(Object from, Converter converter) { static LocalDateTime toLocalDateTime(Object from, Converter converter) { return toZonedDateTime(from, converter).toLocalDateTime(); } - - static LocalTime toLocalTime(Object from, Converter converter) { - return toZonedDateTime(from, converter).toLocalTime(); - } - + static ZonedDateTime toZonedDateTime(Object from, Converter converter) { return toInstant(from, converter).atZone(converter.getOptions().getZoneId()); } diff --git a/src/test/java/com/cedarsoftware/util/convert/ConverterEverythingTest.java b/src/test/java/com/cedarsoftware/util/convert/ConverterEverythingTest.java index 4f21e839..6214f7c5 100644 --- a/src/test/java/com/cedarsoftware/util/convert/ConverterEverythingTest.java +++ b/src/test/java/com/cedarsoftware/util/convert/ConverterEverythingTest.java @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Date; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -76,6 +77,7 @@ class ConverterEverythingTest { private static final String TOKYO = "Asia/Tokyo"; private static final ZoneId TOKYO_Z = ZoneId.of(TOKYO); private static final TimeZone TOKYO_TZ = TimeZone.getTimeZone(TOKYO_Z); + private static final Set> immutable = new HashSet<>(); private Converter converter; private final ConverterOptions options = new ConverterOptions() { public ZoneId getZoneId() { @@ -89,6 +91,38 @@ public ZoneId getZoneId() { // Useful values for input long now = System.currentTimeMillis(); + // List classes that should be checked for immutability + immutable.add(byte.class); + immutable.add(Byte.class); + immutable.add(short.class); + immutable.add(Short.class); + immutable.add(int.class); + immutable.add(Integer.class); + immutable.add(long.class); + immutable.add(Long.class); + immutable.add(float.class); + immutable.add(Float.class); + immutable.add(double.class); + immutable.add(Double.class); + immutable.add(boolean.class); + immutable.add(Boolean.class); + immutable.add(char.class); + immutable.add(Character.class); + immutable.add(BigInteger.class); + immutable.add(BigDecimal.class); + immutable.add(LocalTime.class); + immutable.add(LocalDate.class); + immutable.add(LocalDateTime.class); + immutable.add(ZonedDateTime.class); + immutable.add(OffsetDateTime.class); + immutable.add(Instant.class); + immutable.add(Duration.class); + immutable.add(Period.class); + immutable.add(Month.class); + immutable.add(Year.class); + immutable.add(MonthDay.class); + immutable.add(YearMonth.class); + loadByteTest(); loadShortTests(); loadIntegerTests(); @@ -102,6 +136,7 @@ public ZoneId getZoneId() { loadInstantTests(); loadDateTests(); loadSqlDateTests(); + loadCalendarTests(); loadDurationTests(); loadOffsetDateTimeTests(); loadMonthDayTests(); @@ -111,11 +146,81 @@ public ZoneId getZoneId() { loadZoneIdTests(); loadTimestampTests(now); loadLocalDateTests(); + loadLocalTimeTests(); loadLocalDateTimeTests(); loadZoneDateTimeTests(); loadZoneOffsetTests(); loadStringTests(); loadAtomicLongTests(); + loadAtomicIntegerTests(); + loadAtomicBooleanTests(); + loadMapTests(); + } + + /** + * Map + */ + private static void loadMapTests() { + TEST_DB.put(pair(Void.class, Map.class), new Object[][]{ + {null, null} + }); + } + + /** + * AtomicBoolean + */ + private static void loadAtomicBooleanTests() { + TEST_DB.put(pair(Void.class, AtomicBoolean.class), new Object[][]{ + {null, null} + }); + TEST_DB.put(pair(AtomicBoolean.class, AtomicBoolean.class), new Object[][] { + { new AtomicBoolean(false), new AtomicBoolean(false)}, + { new AtomicBoolean(true), new AtomicBoolean(true)}, + }); + TEST_DB.put(pair(AtomicInteger.class, AtomicBoolean.class), new Object[][] { + { new AtomicInteger(-1), new AtomicBoolean(true)}, + { new AtomicInteger(0), new AtomicBoolean(false), true}, + { new AtomicInteger(1), new AtomicBoolean(true), true}, + }); + TEST_DB.put(pair(AtomicLong.class, AtomicBoolean.class), new Object[][] { + { new AtomicLong((byte)-1), new AtomicBoolean(true)}, + { new AtomicLong((byte)0), new AtomicBoolean(false), true}, + { new AtomicLong((byte)1), new AtomicBoolean(true), true}, + }); + TEST_DB.put(pair(BigDecimal.class, AtomicBoolean.class), new Object[][] { + { new BigDecimal("-1.1"), new AtomicBoolean(true)}, + { BigDecimal.valueOf(-1), new AtomicBoolean(true)}, + { BigDecimal.ZERO, new AtomicBoolean(false), true}, + { BigDecimal.valueOf(1), new AtomicBoolean(true), true}, + { new BigDecimal("1.1"), new AtomicBoolean(true)}, + }); + TEST_DB.put(pair(Map.class, AtomicBoolean.class), new Object[][] { + { mapOf("_v", "true"), new AtomicBoolean(true)}, + { mapOf("_v", true), new AtomicBoolean(true)}, + { mapOf("_v", "false"), new AtomicBoolean(false)}, + { mapOf("_v", false), new AtomicBoolean(false)}, + { mapOf("_v", BigInteger.valueOf(1)), new AtomicBoolean(true)}, + { mapOf("_v", BigDecimal.ZERO), new AtomicBoolean(false)}, + }); + } + + /** + * AtomicInteger + */ + private static void loadAtomicIntegerTests() { + TEST_DB.put(pair(Void.class, AtomicInteger.class), new Object[][]{ + {null, null} + }); + TEST_DB.put(pair(AtomicInteger.class, AtomicInteger.class), new Object[][] { + { new AtomicInteger(1), new AtomicInteger((byte)1), true} + }); + TEST_DB.put(pair(AtomicLong.class, AtomicInteger.class), new Object[][] { + { new AtomicLong(Integer.MIN_VALUE), new AtomicInteger(Integer.MIN_VALUE), true}, + { new AtomicLong(-1), new AtomicInteger((byte)-1), true}, + { new AtomicLong(0), new AtomicInteger(0), true}, + { new AtomicLong(1), new AtomicInteger((byte)1), true}, + { new AtomicLong(Integer.MAX_VALUE), new AtomicInteger(Integer.MAX_VALUE), true}, + }); } /** @@ -125,6 +230,9 @@ private static void loadAtomicLongTests() { TEST_DB.put(pair(Void.class, AtomicLong.class), new Object[][]{ {null, null} }); + TEST_DB.put(pair(AtomicLong.class, AtomicLong.class), new Object[][]{ + {new AtomicLong(16), new AtomicLong(16)} + }); TEST_DB.put(pair(Instant.class, AtomicLong.class), new Object[][]{ {Instant.parse("0000-01-01T00:00:00Z"), new AtomicLong(-62167219200000L), true}, {Instant.parse("0000-01-01T00:00:00.001Z"), new AtomicLong(-62167219199999L), true}, @@ -501,6 +609,11 @@ private static void loadLocalDateTimeTests() { TEST_DB.put(pair(LocalDateTime.class, LocalDateTime.class), new Object[][]{ {LocalDateTime.of(1970, 1, 1, 0, 0), LocalDateTime.of(1970, 1, 1, 0, 0), true} }); + TEST_DB.put(pair(AtomicLong.class, LocalDateTime.class), new Object[][]{ + {new AtomicLong(-1), LocalDateTime.parse("1969-12-31T23:59:59.999").atZone(ZoneId.of("UTC")).withZoneSameInstant(TOKYO_Z).toLocalDateTime(), true}, + {new AtomicLong(0), LocalDateTime.parse("1970-01-01T00:00:00").atZone(ZoneId.of("UTC")).withZoneSameInstant(TOKYO_Z).toLocalDateTime(), true}, + {new AtomicLong(1), LocalDateTime.parse("1970-01-01T00:00:00.001").atZone(ZoneId.of("UTC")).withZoneSameInstant(TOKYO_Z).toLocalDateTime(), true}, + }); TEST_DB.put(pair(Double.class, LocalDateTime.class), new Object[][]{ {-0.000000001, LocalDateTime.parse("1969-12-31T23:59:59.999999999").atZone(ZoneId.of("UTC")).withZoneSameInstant(TOKYO_Z).toLocalDateTime()}, // IEEE-754 prevents perfect symmetry {0d, LocalDateTime.parse("1970-01-01T00:00:00").atZone(ZoneId.of("UTC")).withZoneSameInstant(TOKYO_Z).toLocalDateTime(), true}, @@ -515,6 +628,69 @@ private static void loadLocalDateTimeTests() { }); } + /** + * LocalTime + */ + private static void loadLocalTimeTests() { + TEST_DB.put(pair(Void.class, LocalTime.class), new Object[][]{ + {null, null}, + }); + TEST_DB.put(pair(LocalTime.class, LocalTime.class), new Object[][]{ + { LocalTime.parse("12:34:56"), LocalTime.parse("12:34:56"), true} + }); + TEST_DB.put(pair(Integer.class, LocalTime.class), new Object[][]{ + { -1, new IllegalArgumentException("value [-1]")}, + { 0, LocalTime.parse("00:00:00"), true}, + { 1, LocalTime.parse("00:00:00.001"), true}, + { 86399999, LocalTime.parse("23:59:59.999"), true}, + { 86400000, new IllegalArgumentException("value [86400000]")}, + }); + TEST_DB.put(pair(Long.class, LocalTime.class), new Object[][]{ + { -1L, new IllegalArgumentException("value [-1]")}, + { 0L, LocalTime.parse("00:00:00"), true}, + { 1L, LocalTime.parse("00:00:00.001"), true}, + { 86399999L, LocalTime.parse("23:59:59.999"), true}, + { 86400000L, new IllegalArgumentException("value [86400000]")}, + }); + TEST_DB.put(pair(Double.class, LocalTime.class), new Object[][]{ + { -0.000000001, new IllegalArgumentException("value [-1.0E-9]")}, + { 0.0, LocalTime.parse("00:00:00"), true}, + { 0.000000001, LocalTime.parse("00:00:00.000000001"), true}, + { 1.0, LocalTime.parse("00:00:01"), true}, + { 86399.999999999, LocalTime.parse("23:59:59.999999999"), true}, + { 86400.0, new IllegalArgumentException("value [86400.0]")}, + }); + TEST_DB.put(pair(AtomicInteger.class, LocalTime.class), new Object[][]{ + { new AtomicInteger(-1), new IllegalArgumentException("value [-1]")}, + { new AtomicInteger(0), LocalTime.parse("00:00:00"), true}, + { new AtomicInteger(1), LocalTime.parse("00:00:00.001"), true}, + { new AtomicInteger(86399999), LocalTime.parse("23:59:59.999"), true}, + { new AtomicInteger(86400000), new IllegalArgumentException("value [86400000]")}, + }); + TEST_DB.put(pair(AtomicLong.class, LocalTime.class), new Object[][]{ + { new AtomicLong(-1), new IllegalArgumentException("value [-1]")}, + { new AtomicLong(0), LocalTime.parse("00:00:00"), true}, + { new AtomicLong(1), LocalTime.parse("00:00:00.001"), true}, + { new AtomicLong(86399999), LocalTime.parse("23:59:59.999"), true}, + { new AtomicLong(86400000), new IllegalArgumentException("value [86400000]")}, + }); + TEST_DB.put(pair(BigInteger.class, LocalTime.class), new Object[][]{ + { BigInteger.valueOf(-1), new IllegalArgumentException("value [-1]")}, + { BigInteger.valueOf(0), LocalTime.parse("00:00:00"), true}, + { BigInteger.valueOf(1), LocalTime.parse("00:00:00.000000001"), true}, + { BigInteger.valueOf(86399999999999L), LocalTime.parse("23:59:59.999999999"), true}, + { BigInteger.valueOf(86400000000000L), new IllegalArgumentException("value [86400000000000]")}, + }); + TEST_DB.put(pair(BigDecimal.class, LocalTime.class), new Object[][]{ + { BigDecimal.valueOf(-0.000000001), new IllegalArgumentException("value [-0.0000000010]")}, + { BigDecimal.valueOf(0), LocalTime.parse("00:00:00"), true}, + { BigDecimal.valueOf(0.000000001), LocalTime.parse("00:00:00.000000001"), true}, + { BigDecimal.valueOf(1), LocalTime.parse("00:00:01"), true}, + { BigDecimal.valueOf(86399.999999999), LocalTime.parse("23:59:59.999999999"), true}, + { BigDecimal.valueOf(86400.0), new IllegalArgumentException("value [86400.0]")}, + }); + } + /** * LocalDate */ @@ -532,6 +708,13 @@ private static void loadLocalDateTests() { {53999.999, LocalDate.parse("1970-01-01")}, // Showing that there is a wide range of numbers that will convert to this date {54000d, LocalDate.parse("1970-01-02"), true}, }); + TEST_DB.put(pair(AtomicLong.class, LocalDate.class), new Object[][]{ // options timezone is factored in (86,400 seconds per day) + {new AtomicLong(-118800000), LocalDate.parse("1969-12-31"), true}, + {new AtomicLong(-32400000), LocalDate.parse("1970-01-01"), true}, + {new AtomicLong(0), LocalDate.parse("1970-01-01")}, // Showing that there is a wide range of numbers that will convert to this date + {new AtomicLong(53999999), LocalDate.parse("1970-01-01")}, // Showing that there is a wide range of numbers that will convert to this date + {new AtomicLong(54000000), LocalDate.parse("1970-01-02"), true}, + }); TEST_DB.put(pair(BigInteger.class, LocalDate.class), new Object[][]{ // options timezone is factored in (86,400 seconds per day) // These are all in the same date range {BigInteger.ZERO, ZonedDateTime.parse("1970-01-01T00:00:00Z").withZoneSameInstant(TOKYO_Z).toLocalDate() }, @@ -904,6 +1087,31 @@ private static void loadDateTests() { {null, null} }); // No identity test for Date, as it is mutable + TEST_DB.put(pair(AtomicLong.class, Date.class), new Object[][]{ + {new AtomicLong(Long.MIN_VALUE), new Date(Long.MIN_VALUE), true}, + {new AtomicLong(-1), new Date(-1), true}, + {new AtomicLong(0), new Date(0), true}, + {new AtomicLong(1), new Date(1), true}, + {new AtomicLong(Long.MAX_VALUE), new Date(Long.MAX_VALUE), true}, + }); + } + + /** + * Calendar + */ + private static void loadCalendarTests() { + TEST_DB.put(pair(Void.class, Calendar.class), new Object[][]{ + {null, null} + }); + TEST_DB.put(pair(AtomicLong.class, Calendar.class), new Object[][]{ + {new AtomicLong(0), (Supplier) () -> { + Calendar cal = Calendar.getInstance(); + cal.clear(); + cal.setTimeZone(TOKYO_TZ); + cal.setTimeInMillis(0); + return cal; + }, true} + }); } /** @@ -940,6 +1148,20 @@ private static void loadBigDecimalTests() { TEST_DB.put(pair(String.class, BigDecimal.class), new Object[][]{ {"3.1415926535897932384626433", new BigDecimal("3.1415926535897932384626433"), true} }); + TEST_DB.put(pair(AtomicInteger.class, BigDecimal.class), new Object[][] { + { new AtomicInteger(Integer.MIN_VALUE), BigDecimal.valueOf(Integer.MIN_VALUE), true}, + { new AtomicInteger(-1), BigDecimal.valueOf(-1), true}, + { new AtomicInteger(0), BigDecimal.ZERO, true}, + { new AtomicInteger(1), BigDecimal.valueOf(1), true}, + { new AtomicInteger(Integer.MAX_VALUE), BigDecimal.valueOf(Integer.MAX_VALUE), true}, + }); + TEST_DB.put(pair(AtomicLong.class, BigDecimal.class), new Object[][] { + { new AtomicLong(Long.MIN_VALUE), BigDecimal.valueOf(Long.MIN_VALUE), true}, + { new AtomicLong(-1), BigDecimal.valueOf(-1), true}, + { new AtomicLong(0), BigDecimal.ZERO, true}, + { new AtomicLong(1), BigDecimal.valueOf(1), true}, + { new AtomicLong(Long.MAX_VALUE), BigDecimal.valueOf(Long.MAX_VALUE), true}, + }); TEST_DB.put(pair(Date.class, BigDecimal.class), new Object[][]{ {Date.from(Instant.parse("0000-01-01T00:00:00Z")), new BigDecimal("-62167219200"), true}, {Date.from(Instant.parse("0000-01-01T00:00:00.001Z")), new BigDecimal("-62167219199.999"), true}, @@ -1400,35 +1622,35 @@ private static void loadBooleanTests() { {'0', false}, }); TEST_DB.put(pair(AtomicBoolean.class, Boolean.class), new Object[][]{ - {new AtomicBoolean(true), true}, - {new AtomicBoolean(false), false}, + {new AtomicBoolean(true), true, true}, + {new AtomicBoolean(false), false, true}, }); TEST_DB.put(pair(AtomicInteger.class, Boolean.class), new Object[][]{ {new AtomicInteger(-2), true}, {new AtomicInteger(-1), true}, - {new AtomicInteger(0), false}, - {new AtomicInteger(1), true}, + {new AtomicInteger(0), false, true}, + {new AtomicInteger(1), true, true}, {new AtomicInteger(2), true}, }); TEST_DB.put(pair(AtomicLong.class, Boolean.class), new Object[][]{ {new AtomicLong(-2), true}, {new AtomicLong(-1), true}, - {new AtomicLong(0), false}, - {new AtomicLong(1), true}, + {new AtomicLong(0), false, true}, + {new AtomicLong(1), true, true}, {new AtomicLong(2), true}, }); TEST_DB.put(pair(BigInteger.class, Boolean.class), new Object[][]{ {BigInteger.valueOf(-2), true}, {BigInteger.valueOf(-1), true}, - {BigInteger.ZERO, false}, - {BigInteger.valueOf(1), true}, + {BigInteger.ZERO, false, true}, + {BigInteger.valueOf(1), true, true}, {BigInteger.valueOf(2), true}, }); TEST_DB.put(pair(BigDecimal.class, Boolean.class), new Object[][]{ {BigDecimal.valueOf(-2L), true}, {BigDecimal.valueOf(-1L), true}, - {BigDecimal.valueOf(0L), false}, - {BigDecimal.valueOf(1L), true}, + {BigDecimal.valueOf(0L), false, true}, + {BigDecimal.valueOf(1L), true, true}, {BigDecimal.valueOf(2L), true}, }); TEST_DB.put(pair(Number.class, Boolean.class), new Object[][]{ @@ -1447,13 +1669,13 @@ private static void loadBooleanTests() { }); TEST_DB.put(pair(String.class, Boolean.class), new Object[][]{ {"0", false}, - {"false", false}, + {"false", false, true}, {"FaLse", false}, {"FALSE", false}, {"F", false}, {"f", false}, {"1", true}, - {"true", true}, + {"true", true, true}, {"TrUe", true}, {"TRUE", true}, {"T", true}, @@ -2515,109 +2737,105 @@ private static void loadByteTest() { {Byte.MAX_VALUE, Byte.MAX_VALUE}, }); TEST_DB.put(pair(Short.class, Byte.class), new Object[][]{ - {(short) -1, (byte) -1}, - {(short) 0, (byte) 0}, - {(short) 1, (byte) 1}, - {(short) -128, Byte.MIN_VALUE}, - {(short) 127, Byte.MAX_VALUE}, + {(short) -1, (byte) -1, true}, + {(short) 0, (byte) 0, true}, + {(short) 1, (byte) 1, true}, + {(short) -128, Byte.MIN_VALUE, true}, + {(short) 127, Byte.MAX_VALUE, true}, {(short) -129, Byte.MAX_VALUE}, // verify wrap around {(short) 128, Byte.MIN_VALUE}, // verify wrap around }); TEST_DB.put(pair(Integer.class, Byte.class), new Object[][]{ - {-1, (byte) -1}, - {0, (byte) 0}, - {1, (byte) 1}, - {-128, Byte.MIN_VALUE}, - {127, Byte.MAX_VALUE}, + {-1, (byte) -1, true}, + {0, (byte) 0, true}, + {1, (byte) 1, true}, + {-128, Byte.MIN_VALUE, true}, + {127, Byte.MAX_VALUE, true}, {-129, Byte.MAX_VALUE}, // verify wrap around {128, Byte.MIN_VALUE}, // verify wrap around }); TEST_DB.put(pair(Long.class, Byte.class), new Object[][]{ - {-1L, (byte) -1}, - {0L, (byte) 0}, - {1L, (byte) 1}, - {-128L, Byte.MIN_VALUE}, - {127L, Byte.MAX_VALUE}, + {-1L, (byte) -1, true}, + {0L, (byte) 0, true}, + {1L, (byte) 1, true}, + {-128L, Byte.MIN_VALUE, true}, + {127L, Byte.MAX_VALUE, true}, {-129L, Byte.MAX_VALUE}, // verify wrap around {128L, Byte.MIN_VALUE} // verify wrap around }); TEST_DB.put(pair(Float.class, Byte.class), new Object[][]{ - {-1f, (byte) -1}, + {-1f, (byte) -1, true}, {-1.99f, (byte) -1}, {-1.1f, (byte) -1}, - {0f, (byte) 0}, - {1f, (byte) 1}, + {0f, (byte) 0, true}, + {1f, (byte) 1, true}, {1.1f, (byte) 1}, {1.999f, (byte) 1}, - {-128f, Byte.MIN_VALUE}, - {127f, Byte.MAX_VALUE}, + {-128f, Byte.MIN_VALUE, true}, + {127f, Byte.MAX_VALUE, true}, {-129f, Byte.MAX_VALUE}, // verify wrap around {128f, Byte.MIN_VALUE} // verify wrap around }); TEST_DB.put(pair(Double.class, Byte.class), new Object[][]{ - {-1d, (byte) -1}, + {-1d, (byte) -1, true}, {-1.99, (byte) -1}, {-1.1, (byte) -1}, - {0d, (byte) 0}, + {0d, (byte) 0, true}, {1d, (byte) 1}, {1.1, (byte) 1}, {1.999, (byte) 1}, - {-128d, Byte.MIN_VALUE}, - {127d, Byte.MAX_VALUE}, + {-128d, Byte.MIN_VALUE, true}, + {127d, Byte.MAX_VALUE, true}, {-129d, Byte.MAX_VALUE}, // verify wrap around {128d, Byte.MIN_VALUE} // verify wrap around }); TEST_DB.put(pair(Boolean.class, Byte.class), new Object[][]{ - {true, (byte) 1}, - {false, (byte) 0}, + {true, (byte) 1, true}, + {false, (byte) 0, true}, }); TEST_DB.put(pair(Character.class, Byte.class), new Object[][]{ - {'1', (byte) 49}, - {'0', (byte) 48}, - {(char) 1, (byte) 1}, - {(char) 0, (byte) 0}, + {'1', (byte) 49, true}, + {'0', (byte) 48, true}, + {(char) 1, (byte) 1, true}, + {(char) 0, (byte) 0, true}, }); TEST_DB.put(pair(AtomicBoolean.class, Byte.class), new Object[][]{ - {new AtomicBoolean(true), (byte) 1}, - {new AtomicBoolean(false), (byte) 0}, + {new AtomicBoolean(true), (byte) 1, true}, + {new AtomicBoolean(false), (byte) 0, true}, }); TEST_DB.put(pair(AtomicInteger.class, Byte.class), new Object[][]{ - {new AtomicInteger(-1), (byte) -1}, - {new AtomicInteger(0), (byte) 0}, - {new AtomicInteger(1), (byte) 1}, - {new AtomicInteger(-128), Byte.MIN_VALUE}, - {new AtomicInteger(127), Byte.MAX_VALUE}, - {new AtomicInteger(-129), Byte.MAX_VALUE}, - {new AtomicInteger(128), Byte.MIN_VALUE}, + {new AtomicInteger(-1), (byte) -1, true}, + {new AtomicInteger(0), (byte) 0, true}, + {new AtomicInteger(1), (byte) 1, true}, + {new AtomicInteger(-128), Byte.MIN_VALUE, true}, + {new AtomicInteger(127), Byte.MAX_VALUE, true}, }); TEST_DB.put(pair(AtomicLong.class, Byte.class), new Object[][]{ - {new AtomicLong(-1), (byte) -1}, - {new AtomicLong(0), (byte) 0}, - {new AtomicLong(1), (byte) 1}, - {new AtomicLong(-128), Byte.MIN_VALUE}, - {new AtomicLong(127), Byte.MAX_VALUE}, - {new AtomicLong(-129), Byte.MAX_VALUE}, - {new AtomicLong(128), Byte.MIN_VALUE}, + {new AtomicLong(-1), (byte) -1, true}, + {new AtomicLong(0), (byte) 0, true}, + {new AtomicLong(1), (byte) 1, true}, + {new AtomicLong(-128), Byte.MIN_VALUE, true}, + {new AtomicLong(127), Byte.MAX_VALUE, true}, }); TEST_DB.put(pair(BigInteger.class, Byte.class), new Object[][]{ - {new BigInteger("-1"), (byte) -1}, - {BigInteger.ZERO, (byte) 0}, - {new BigInteger("1"), (byte) 1}, - {new BigInteger("-128"), Byte.MIN_VALUE}, - {new BigInteger("127"), Byte.MAX_VALUE}, + {new BigInteger("-1"), (byte) -1, true}, + {BigInteger.ZERO, (byte) 0, true}, + {new BigInteger("1"), (byte) 1, true}, + {new BigInteger("-128"), Byte.MIN_VALUE, true}, + {new BigInteger("127"), Byte.MAX_VALUE, true}, {new BigInteger("-129"), Byte.MAX_VALUE}, {new BigInteger("128"), Byte.MIN_VALUE}, }); TEST_DB.put(pair(BigDecimal.class, Byte.class), new Object[][]{ - {new BigDecimal("-1"), (byte) -1}, + {new BigDecimal("-1"), (byte) -1, true}, {new BigDecimal("-1.1"), (byte) -1}, {new BigDecimal("-1.9"), (byte) -1}, - {BigDecimal.ZERO, (byte) 0}, - {new BigDecimal("1"), (byte) 1}, + {BigDecimal.ZERO, (byte) 0, true}, + {new BigDecimal("1"), (byte) 1, true}, {new BigDecimal("1.1"), (byte) 1}, {new BigDecimal("1.9"), (byte) 1}, - {new BigDecimal("-128"), Byte.MIN_VALUE}, - {new BigDecimal("127"), Byte.MAX_VALUE}, + {new BigDecimal("-128"), Byte.MIN_VALUE, true}, + {new BigDecimal("127"), Byte.MAX_VALUE, true}, {new BigDecimal("-129"), Byte.MAX_VALUE}, {new BigDecimal("128"), Byte.MIN_VALUE}, }); @@ -2650,18 +2868,18 @@ private static void loadByteTest() { {mapOf("_v", mapOf("_v", 128L)), Byte.MIN_VALUE}, // Prove use of recursive call to .convert() }); TEST_DB.put(pair(Year.class, Byte.class), new Object[][]{ - {Year.of(2024), new IllegalArgumentException("Unsupported conversion, source type [Year (2024)] target type 'Byte'")}, + {Year.of(2024), new IllegalArgumentException("Unsupported conversion, source type [Year (2024)] target type 'Byte'") }, }); TEST_DB.put(pair(String.class, Byte.class), new Object[][]{ - {"-1", (byte) -1}, + {"-1", (byte) -1, true}, {"-1.1", (byte) -1}, {"-1.9", (byte) -1}, - {"0", (byte) 0}, - {"1", (byte) 1}, + {"0", (byte) 0, true}, + {"1", (byte) 1, true}, {"1.1", (byte) 1}, {"1.9", (byte) 1}, - {"-128", (byte) -128}, - {"127", (byte) 127}, + {"-128", (byte) -128, true}, + {"127", (byte) 127, true}, {"", (byte) 0}, {" ", (byte) 0}, {"crapola", new IllegalArgumentException("Value 'crapola' not parseable as a byte value or outside -128 to 127")}, @@ -2714,6 +2932,11 @@ private static Stream generateTestEverythingParams() { for (Map.Entry, Class>, Object[][]> entry : TEST_DB.entrySet()) { Class sourceClass = entry.getKey().getKey(); Class targetClass = entry.getKey().getValue(); + + // Skip Atomic's to Map - assertEquals() does not know to call .get() on the value side of the Map. + if (isHardCase(sourceClass, targetClass)) { + continue; + } String sourceName = Converter.getShortName(sourceClass); String targetName = Converter.getShortName(targetClass); Object[][] testData = entry.getValue(); @@ -2735,6 +2958,10 @@ private static Stream generateTestEverythingParamsInReverse() { for (Map.Entry, Class>, Object[][]> entry : TEST_DB.entrySet()) { Class sourceClass = entry.getKey().getKey(); Class targetClass = entry.getKey().getValue(); + + if (isHardCase(sourceClass, targetClass)) { + continue; + } String sourceName = Converter.getShortName(sourceClass); String targetName = Converter.getShortName(targetClass); @@ -2771,7 +2998,7 @@ void testConvert(String shortNameSource, String shortNameTarget, Object source, assert target == null || target instanceof Throwable || ClassUtilities.toPrimitiveWrapperClass(targetClass).isInstance(target) : "target type mismatch ==> Expected: " + shortNameTarget + ", Actual: " + Converter.getShortName(target.getClass()); // if the source/target are the same Class, then ensure identity lambda is used. - if (sourceClass.equals(targetClass)) { + if (sourceClass.equals(targetClass) && immutable.contains(sourceClass)) { assertSame(source, converter.convert(source, targetClass)); } @@ -2784,7 +3011,13 @@ void testConvert(String shortNameSource, String shortNameTarget, Object source, // Assert values are equals Object actual = converter.convert(source, targetClass); try { - if (target instanceof AtomicLong) { + if (target instanceof AtomicBoolean) { + assertEquals(((AtomicBoolean) target).get(), ((AtomicBoolean) actual).get()); + updateStat(pair(sourceClass, targetClass), true); + } else if (target instanceof AtomicInteger) { + assertEquals(((AtomicInteger) target).get(), ((AtomicInteger) actual).get()); + updateStat(pair(sourceClass, targetClass), true); + } else if (target instanceof AtomicLong) { assertEquals(((AtomicLong) target).get(), ((AtomicLong) actual).get()); updateStat(pair(sourceClass, targetClass), true); } else if (target instanceof BigDecimal) { @@ -2793,7 +3026,7 @@ void testConvert(String shortNameSource, String shortNameTarget, Object source, } updateStat(pair(sourceClass, targetClass), true); } else { - assertEquals(target, actual); + assertEquals(actual, target); updateStat(pair(sourceClass, targetClass), true); } } @@ -2803,11 +3036,17 @@ void testConvert(String shortNameSource, String shortNameTarget, Object source, } } } - + private static void updateStat(Map.Entry, Class> pair, boolean state) { STAT_DB.put(pair, state); } + // Rare pairings that cannot be tested without drilling into the class - Atomic's require .get() to be called, + // so an Atomic inside a Map is a hard-case. + private static boolean isHardCase(Class sourceClass, Class targetClass) { + return targetClass.equals(Map.class) && (sourceClass.equals(AtomicBoolean.class) || sourceClass.equals(AtomicInteger.class) || sourceClass.equals(AtomicLong.class)); + } + @BeforeAll static void statPrep() { Map, Set>> map = com.cedarsoftware.util.Converter.allSupportedConversions(); @@ -2830,6 +3069,11 @@ static void printStats() { Map.Entry, Class> pair = entry.getKey(); boolean value = entry.getValue(); if (!value) { + Class sourceClass = pair.getKey(); + Class targetClass = pair.getValue(); + if (isHardCase(sourceClass, targetClass)) { + continue; + } missing++; testPairNames.add("\n " + Converter.getShortName(pair.getKey()) + " ==> " + Converter.getShortName(pair.getValue())); } diff --git a/src/test/java/com/cedarsoftware/util/convert/ConverterTest.java b/src/test/java/com/cedarsoftware/util/convert/ConverterTest.java index 65230c1e..1e3d05e3 100644 --- a/src/test/java/com/cedarsoftware/util/convert/ConverterTest.java +++ b/src/test/java/com/cedarsoftware/util/convert/ConverterTest.java @@ -43,6 +43,7 @@ import static com.cedarsoftware.util.ArrayUtilities.EMPTY_CHAR_ARRAY; import static com.cedarsoftware.util.Converter.zonedDateTimeToMillis; import static com.cedarsoftware.util.StringUtilities.EMPTY; +import static com.cedarsoftware.util.convert.Converter.VALUE; 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; @@ -1617,16 +1618,6 @@ void testLongToBigInteger(Object source, Number number) assertThat(actual).isEqualTo(BigInteger.valueOf(expected)); } - - @ParameterizedTest - @MethodSource("epochMillis_withLocalDateInformation") - void testLongToLocalTime(long epochMilli, ZoneId zoneId, LocalDate expected) - { - Converter converter = new Converter(createCustomZones(zoneId)); - LocalTime actual = converter.convert(epochMilli, LocalTime.class); - - assertThat(actual).isEqualTo(Instant.ofEpochMilli(epochMilli).atZone(zoneId).toLocalTime()); - } @ParameterizedTest @MethodSource("localDateTimeConversion_params") @@ -3511,14 +3502,14 @@ void testByteToMap() byte b1 = (byte) 16; Map map = this.converter.convert(b1, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), (byte)16); - assert map.get(Converter.VALUE).getClass().equals(Byte.class); + assertEquals(map.get(VALUE), (byte)16); + assert map.get(VALUE).getClass().equals(Byte.class); Byte b2 = (byte) 16; map = this.converter.convert(b2, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), (byte)16); - assert map.get(Converter.VALUE).getClass().equals(Byte.class); + assertEquals(map.get(VALUE), (byte)16); + assert map.get(VALUE).getClass().equals(Byte.class); } @Test @@ -3527,14 +3518,14 @@ void testShortToMap() short s1 = (short) 1600; Map map = this.converter.convert(s1, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), (short)1600); - assert map.get(Converter.VALUE).getClass().equals(Short.class); + assertEquals(map.get(VALUE), (short)1600); + assert map.get(VALUE).getClass().equals(Short.class); Short s2 = (short) 1600; map = this.converter.convert(s2, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), (short)1600); - assert map.get(Converter.VALUE).getClass().equals(Short.class); + assertEquals(map.get(VALUE), (short)1600); + assert map.get(VALUE).getClass().equals(Short.class); } @Test @@ -3543,14 +3534,14 @@ void testIntegerToMap() int s1 = 1234567; Map map = this.converter.convert(s1, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), 1234567); - assert map.get(Converter.VALUE).getClass().equals(Integer.class); + assertEquals(map.get(VALUE), 1234567); + assert map.get(VALUE).getClass().equals(Integer.class); Integer s2 = 1234567; map = this.converter.convert(s2, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), 1234567); - assert map.get(Converter.VALUE).getClass().equals(Integer.class); + assertEquals(map.get(VALUE), 1234567); + assert map.get(VALUE).getClass().equals(Integer.class); } @Test @@ -3559,14 +3550,14 @@ void testLongToMap() long s1 = 123456789012345L; Map map = this.converter.convert(s1, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), 123456789012345L); - assert map.get(Converter.VALUE).getClass().equals(Long.class); + assertEquals(map.get(VALUE), 123456789012345L); + assert map.get(VALUE).getClass().equals(Long.class); Long s2 = 123456789012345L; map = this.converter.convert(s2, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), 123456789012345L); - assert map.get(Converter.VALUE).getClass().equals(Long.class); + assertEquals(map.get(VALUE), 123456789012345L); + assert map.get(VALUE).getClass().equals(Long.class); } @Test @@ -3575,14 +3566,14 @@ void testFloatToMap() float s1 = 3.141592f; Map map = this.converter.convert(s1, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), 3.141592f); - assert map.get(Converter.VALUE).getClass().equals(Float.class); + assertEquals(map.get(VALUE), 3.141592f); + assert map.get(VALUE).getClass().equals(Float.class); Float s2 = 3.141592f; map = this.converter.convert(s2, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), 3.141592f); - assert map.get(Converter.VALUE).getClass().equals(Float.class); + assertEquals(map.get(VALUE), 3.141592f); + assert map.get(VALUE).getClass().equals(Float.class); } @Test @@ -3591,14 +3582,14 @@ void testDoubleToMap() double s1 = 3.14159265358979d; Map map = this.converter.convert(s1, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), 3.14159265358979d); - assert map.get(Converter.VALUE).getClass().equals(Double.class); + assertEquals(map.get(VALUE), 3.14159265358979d); + assert map.get(VALUE).getClass().equals(Double.class); Double s2 = 3.14159265358979d; map = this.converter.convert(s2, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), 3.14159265358979d); - assert map.get(Converter.VALUE).getClass().equals(Double.class); + assertEquals(map.get(VALUE), 3.14159265358979d); + assert map.get(VALUE).getClass().equals(Double.class); } @Test @@ -3607,14 +3598,14 @@ void testBooleanToMap() boolean s1 = true; Map map = this.converter.convert(s1, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), true); - assert map.get(Converter.VALUE).getClass().equals(Boolean.class); + assertEquals(map.get(VALUE), true); + assert map.get(VALUE).getClass().equals(Boolean.class); Boolean s2 = true; map = this.converter.convert(s2, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), true); - assert map.get(Converter.VALUE).getClass().equals(Boolean.class); + assertEquals(map.get(VALUE), true); + assert map.get(VALUE).getClass().equals(Boolean.class); } @Test @@ -3623,14 +3614,14 @@ void testCharacterToMap() char s1 = 'e'; Map map = this.converter.convert(s1, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), 'e'); - assert map.get(Converter.VALUE).getClass().equals(Character.class); + assertEquals(map.get(VALUE), 'e'); + assert map.get(VALUE).getClass().equals(Character.class); Character s2 = 'e'; map = this.converter.convert(s2, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), 'e'); - assert map.get(Converter.VALUE).getClass().equals(Character.class); + assertEquals(map.get(VALUE), 'e'); + assert map.get(VALUE).getClass().equals(Character.class); } @Test @@ -3639,8 +3630,8 @@ void testBigIntegerToMap() BigInteger bi = BigInteger.valueOf(1234567890123456L); Map map = this.converter.convert(bi, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), bi); - assert map.get(Converter.VALUE).getClass().equals(BigInteger.class); + assertEquals(map.get(VALUE), bi); + assert map.get(VALUE).getClass().equals(BigInteger.class); } @Test @@ -3649,8 +3640,8 @@ void testBigDecimalToMap() BigDecimal bd = new BigDecimal("3.1415926535897932384626433"); Map map = this.converter.convert(bd, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), bd); - assert map.get(Converter.VALUE).getClass().equals(BigDecimal.class); + assertEquals(map.get(VALUE), bd); + assert map.get(VALUE).getClass().equals(BigDecimal.class); } @Test @@ -3659,8 +3650,8 @@ void testAtomicBooleanToMap() AtomicBoolean ab = new AtomicBoolean(true); Map map = this.converter.convert(ab, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), ab); - assert map.get(Converter.VALUE).getClass().equals(AtomicBoolean.class); + assertEquals(map.get(VALUE), ab); + assert map.get(VALUE).getClass().equals(AtomicBoolean.class); } @Test @@ -3669,8 +3660,8 @@ void testAtomicIntegerToMap() AtomicInteger ai = new AtomicInteger(123456789); Map map = this.converter.convert(ai, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), ai); - assert map.get(Converter.VALUE).getClass().equals(AtomicInteger.class); + assertEquals(map.get(VALUE), ai); + assert map.get(VALUE).getClass().equals(AtomicInteger.class); } @Test @@ -3679,8 +3670,8 @@ void testAtomicLongToMap() AtomicLong al = new AtomicLong(12345678901234567L); Map map = this.converter.convert(al, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), al); - assert map.get(Converter.VALUE).getClass().equals(AtomicLong.class); + assertEquals(map.get(VALUE), al); + assert map.get(VALUE).getClass().equals(AtomicLong.class); } @Test @@ -3689,7 +3680,7 @@ void testClassToMap() Class clazz = ConverterTest.class; Map map = this.converter.convert(clazz, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), clazz); + assertEquals(map.get(VALUE), clazz); } @Test @@ -3698,8 +3689,8 @@ void testUUIDToMap() UUID uuid = new UUID(1L, 2L); Map map = this.converter.convert(uuid, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), uuid); - assert map.get(Converter.VALUE).getClass().equals(UUID.class); + assertEquals(map.get(VALUE), uuid); + assert map.get(VALUE).getClass().equals(UUID.class); } @Test @@ -3708,8 +3699,8 @@ void testCalendarToMap() Calendar cal = Calendar.getInstance(); Map map = this.converter.convert(cal, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), cal); - assert map.get(Converter.VALUE) instanceof Calendar; + assertEquals(map.get(VALUE), cal); + assert map.get(VALUE) instanceof Calendar; } @Test @@ -3718,8 +3709,8 @@ void testDateToMap() Date now = new Date(); Map map = this.converter.convert(now, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), now); - assert map.get(Converter.VALUE).getClass().equals(Date.class); + assertEquals(map.get(VALUE), now); + assert map.get(VALUE).getClass().equals(Date.class); } @Test @@ -3728,8 +3719,8 @@ void testSqlDateToMap() java.sql.Date now = new java.sql.Date(System.currentTimeMillis()); Map map = this.converter.convert(now, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), now); - assert map.get(Converter.VALUE).getClass().equals(java.sql.Date.class); + assertEquals(map.get(VALUE), now); + assert map.get(VALUE).getClass().equals(java.sql.Date.class); } @Test @@ -3738,8 +3729,8 @@ void testTimestampToMap() Timestamp now = new Timestamp(System.currentTimeMillis()); Map map = this.converter.convert(now, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), now); - assert map.get(Converter.VALUE).getClass().equals(Timestamp.class); + assertEquals(map.get(VALUE), now); + assert map.get(VALUE).getClass().equals(Timestamp.class); } @Test @@ -3748,8 +3739,8 @@ void testLocalDateToMap() LocalDate now = LocalDate.now(); Map map = this.converter.convert(now, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), now); - assert map.get(Converter.VALUE).getClass().equals(LocalDate.class); + assertEquals(map.get(VALUE), now); + assert map.get(VALUE).getClass().equals(LocalDate.class); } @Test @@ -3758,8 +3749,8 @@ void testLocalDateTimeToMap() LocalDateTime now = LocalDateTime.now(); Map map = this.converter.convert(now, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), now); - assert map.get(Converter.VALUE).getClass().equals(LocalDateTime.class); + assertEquals(map.get(VALUE), now); + assert map.get(VALUE).getClass().equals(LocalDateTime.class); } @Test @@ -3768,8 +3759,8 @@ void testZonedDateTimeToMap() ZonedDateTime now = ZonedDateTime.now(); Map map = this.converter.convert(now, Map.class); assert map.size() == 1; - assertEquals(map.get(Converter.VALUE), now); - assert map.get(Converter.VALUE).getClass().equals(ZonedDateTime.class); + assertEquals(map.get(VALUE), now); + assert map.get(VALUE).getClass().equals(ZonedDateTime.class); } @Test