diff --git a/src/main/java/com/cedarsoftware/util/DateUtilities.java b/src/main/java/com/cedarsoftware/util/DateUtilities.java index dfccd86d..13c20339 100644 --- a/src/main/java/com/cedarsoftware/util/DateUtilities.java +++ b/src/main/java/com/cedarsoftware/util/DateUtilities.java @@ -157,7 +157,7 @@ private DateUtilities() { * passed in, null will be returned. */ public static Date parseDate(String dateStr) { - if (StringUtilities.isEmpty(dateStr)) { + if (StringUtilities.isWhitespace(dateStr)) { return null; } ZonedDateTime zonedDateTime = parseDate(dateStr, ZoneId.systemDefault(), true); @@ -357,4 +357,4 @@ private static String stripBrackets(String input) { } return input.replaceAll("^\\[|\\]$", ""); } -} \ No newline at end of file +} diff --git a/src/main/java/com/cedarsoftware/util/StringUtilities.java b/src/main/java/com/cedarsoftware/util/StringUtilities.java index 8e8954b4..f70ef6b4 100644 --- a/src/main/java/com/cedarsoftware/util/StringUtilities.java +++ b/src/main/java/com/cedarsoftware/util/StringUtilities.java @@ -1,6 +1,7 @@ package com.cedarsoftware.util; import java.io.UnsupportedEncodingException; +import java.util.Optional; import java.util.Random; /** @@ -31,6 +32,8 @@ public final class StringUtilities }; public static final String FOLDER_SEPARATOR = "/"; + public static final String EMPTY = ""; + /** *

Constructor is declared private since all methods are static.

*/ @@ -39,22 +42,124 @@ private StringUtilities() super(); } - public static boolean equals(final String str1, final String str2) - { - if (str1 == null || str2 == null) - { - return str1 == str2; + /** + * Compares two CharSequences, returning {@code true} if they represent + * equal sequences of characters. + * + *

{@code null}s are handled without exceptions. Two {@code null} + * references are considered to be equal. The comparison is case-sensitive.

+ * + * @param cs1 the first CharSequence, may be {@code null} + * @param cs2 the second CharSequence, may be {@code null} + * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null} + * @see #equalsIgnoreCase(CharSequence, CharSequence) + */ + public static boolean equals(final CharSequence cs1, final CharSequence cs2) { + if (cs1 == cs2) { + return true; + } + if (cs1 == null || cs2 == null) { + return false; + } + if (cs1.length() != cs2.length()) { + return false; + } + if (cs1 instanceof String && cs2 instanceof String) { + return cs1.equals(cs2); + } + // Step-wise comparison + final int length = cs1.length(); + for (int i = 0; i < length; i++) { + if (cs1.charAt(i) != cs2.charAt(i)) { + return false; + } } - return str1.equals(str2); + return true; } - public static boolean equalsIgnoreCase(final String s1, final String s2) - { - if (s1 == null || s2 == null) - { - return s1 == s2; + /** + * Compares two CharSequences, returning {@code true} if they represent + * equal sequences of characters, ignoring case. + * + *

{@code null}s are handled without exceptions. Two {@code null} + * references are considered equal. The comparison is case insensitive.

+ * + * @param cs1 the first CharSequence, may be {@code null} + * @param cs2 the second CharSequence, may be {@code null} + * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null} + * @see #equals(CharSequence, CharSequence) + */ + public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) { + if (cs1 == cs2) { + return true; + } + if (cs1 == null || cs2 == null) { + return false; + } + if (cs1.length() != cs2.length()) { + return false; + } + return regionMatches(cs1, true, 0, cs2, 0, cs1.length()); + } + + /** + * Green implementation of regionMatches. + * + * @param cs the {@link CharSequence} to be processed + * @param ignoreCase whether or not to be case-insensitive + * @param thisStart the index to start on the {@code cs} CharSequence + * @param substring the {@link CharSequence} to be looked for + * @param start the index to start on the {@code substring} CharSequence + * @param length character length of the region + * @return whether the region matched + */ + static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int thisStart, + final CharSequence substring, final int start, final int length) { + Convention.throwIfNull(cs, "cs to be processed cannot be null"); + Convention.throwIfNull(substring, "substring cannot be null"); + + if (cs instanceof String && substring instanceof String) { + return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring, start, length); } - return s1.equalsIgnoreCase(s2); + int index1 = thisStart; + int index2 = start; + int tmpLen = length; + + // Extract these first so we detect NPEs the same as the java.lang.String version + final int srcLen = cs.length() - thisStart; + final int otherLen = substring.length() - start; + + // Check for invalid parameters + if (thisStart < 0 || start < 0 || length < 0) { + return false; + } + + // Check that the regions are long enough + if (srcLen < length || otherLen < length) { + return false; + } + + while (tmpLen-- > 0) { + final char c1 = cs.charAt(index1++); + final char c2 = substring.charAt(index2++); + + if (c1 == c2) { + continue; + } + + if (!ignoreCase) { + return false; + } + + // The real same check as in String.regionMatches(): + final char u1 = Character.toUpperCase(c1); + final char u2 = Character.toUpperCase(c2); + if (u1 != u2 && Character.toLowerCase(u1) != Character.toLowerCase(u2)) { + return false; + } + } + + return true; } public static boolean equalsWithTrim(final String s1, final String s2) @@ -75,41 +180,89 @@ public static boolean equalsIgnoreCaseWithTrim(final String s1, final String s2) return s1.trim().equalsIgnoreCase(s2.trim()); } - public static boolean isEmpty(final String s) + /** + * Checks if a CharSequence is empty (""), null, or only whitespace. + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if the CharSequence is empty or null + */ + public static boolean isEmpty(CharSequence cs) { - return trimLength(s) == 0; + return isWhitespace(cs); } - public static boolean hasContent(final String s) - { - return !(trimLength(s) == 0); // faster than returning !isEmpty() + /** + * Checks if a CharSequence is not empty (""), not null and not whitespace only. + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if the CharSequence is + * not empty and not null and not whitespace only + */ + public static boolean isNotWhitespace(final CharSequence cs) { + return !isWhitespace(cs); } /** - * Use this method when you don't want a length check to - * throw a NullPointerException when + * Checks if a CharSequence is empty (""), null or whitespace only. * - * @param s string to return length of - * @return 0 if string is null, otherwise the length of string. + * @param cs the CharSequence to check, may be null + * @return {@code true} if the CharSequence is null, empty or whitespace only */ - public static int length(final String s) - { - return s == null ? 0 : s.length(); + public static boolean isWhitespace(final CharSequence cs) { + final int strLen = length(cs); + if (strLen == 0) { + return true; + } + for (int i = 0; i < strLen; i++) { + if (!Character.isWhitespace(cs.charAt(i))) { + return false; + } + } + return true; } /** - * Returns the length of the trimmed string. If the length is - * null then it returns 0. + * Checks if a CharSequence is not null, not empty (""), and not only whitespace. + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if the CharSequence is not empty and not null */ - public static int trimLength(final String s) - { - return (s == null) ? 0 : s.trim().length(); + public static boolean isNotEmpty(final CharSequence cs) { + return !isWhitespace(cs); } - public static int lastIndexOf(String path, char ch) - { - if (path == null) - { + /** + * Checks if a CharSequence is not empty (""), not null and not whitespace only. + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if the CharSequence is + * not empty and not null and not whitespace only + */ + public static boolean hasContent(final CharSequence cs) { + return !isWhitespace(cs); + } + + /** + * Gets a CharSequence length or {@code 0} if the CharSequence is {@code null}. + * + * @param cs a CharSequence or {@code null} + * @return CharSequence length or {@code 0} if the CharSequence is {@code null}. + */ + public static int length(final CharSequence cs) { + return cs == null ? 0 : cs.length(); + } + + /** + * @param s a String or {@code null} + * @return the trimmed length of the String or 0 if the string is null. + */ + public static int trimLength(final String s) { + return trimToEmpty(s).length(); + } + + + public static int lastIndexOf(String path, char ch) { + if (path == null) { return -1; } return path.lastIndexOf(ch); @@ -169,7 +322,7 @@ private static char convertDigit(int value) public static int count(String s, char c) { - return count (s, "" + c); + return count (s, EMPTY + c); } /** @@ -268,11 +421,11 @@ public static String wildcardToRegexString(String wildcard) public static int levenshteinDistance(CharSequence s, CharSequence t) { // degenerate cases s - if (s == null || "".equals(s)) + if (s == null || EMPTY.equals(s)) { - return t == null || "".equals(t) ? 0 : t.length(); + return t == null || EMPTY.equals(t) ? 0 : t.length(); } - else if (t == null || "".equals(t)) + else if (t == null || EMPTY.equals(t)) { return s.length(); } @@ -329,11 +482,11 @@ else if (t == null || "".equals(t)) */ public static int damerauLevenshteinDistance(CharSequence source, CharSequence target) { - if (source == null || "".equals(source)) + if (source == null || EMPTY.equals(source)) { - return target == null || "".equals(target) ? 0 : target.length(); + return target == null || EMPTY.equals(target) ? 0 : target.length(); } - else if (target == null || "".equals(target)) + else if (target == null || EMPTY.equals(target)) { return source.length(); } @@ -415,6 +568,7 @@ public static String getRandomString(Random random, int minLen, int maxLen) { StringBuilder s = new StringBuilder(); final int len = minLen + random.nextInt(maxLen - minLen + 1); + for (int i=0; i < len; i++) { s.append(getRandomChar(random, i == 0)); @@ -425,7 +579,7 @@ public static String getRandomString(Random random, int minLen, int maxLen) public static String getRandomChar(Random random, boolean upper) { int r = random.nextInt(26); - return upper ? "" + (char)((int)'A' + r) : "" + (char)((int)'a' + r); + return upper ? EMPTY + (char)((int)'A' + r) : EMPTY + (char)((int)'a' + r); } /** @@ -523,4 +677,48 @@ public static int hashCodeIgnoreCase(String s) } return hash; } + + /** + * Removes control characters (char <= 32) from both + * ends of this String, handling {@code null} by returning + * {@code null}. + * + *

The String is trimmed using {@link String#trim()}. + * Trim removes start and end characters <= 32. + * + * @param str the String to be trimmed, may be null + * @return the trimmed string, {@code null} if null String input + */ + public static String trim(final String str) { + return str == null ? null : str.trim(); + } + + /** + * Trims a string, its null safe and null will return empty string here.. + * @param value string input + * @return String trimmed string, if value was null this will be empty + */ + public static String trimToEmpty(String value) { + return value == null ? EMPTY : value.trim(); + } + + /** + * Trims a string, If the string trims to empty then we return null. + * @param value string input + * @return String, trimmed from value. If the value was empty we return null. + */ + public static String trimToNull(String value) { + final String ts = trim(value); + return isEmpty(ts) ? null : ts; + } + + /** + * Trims a string, If the string trims to empty then we return the default. + * @param value string input + * @param defaultValue value to return on empty or null + * @return trimmed string, or defaultValue when null or empty + */ + public static String trimEmptyToDefault(String value, String defaultValue) { + return Optional.ofNullable(value).map(StringUtilities::trimToNull).orElse(defaultValue); + } } diff --git a/src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversion.java b/src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversions.java similarity index 92% rename from src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversion.java rename to src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversions.java index b5730345..03034ae4 100644 --- a/src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/AtomicBooleanConversions.java @@ -6,7 +6,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; -public class AtomicBooleanConversion { +public class AtomicBooleanConversions { static Byte toByte(Object from, Converter converter, ConverterOptions options) { AtomicBoolean b = (AtomicBoolean) from; @@ -43,11 +43,17 @@ static boolean toBoolean(Object from, Converter converter, ConverterOptions opti return b.get(); } + static AtomicBoolean toAtomicBoolean(Object from, Converter converter, ConverterOptions options) { + AtomicBoolean b = (AtomicBoolean) from; + return new AtomicBoolean(b.get()); + } + static AtomicInteger toAtomicInteger(Object from, Converter converter, ConverterOptions options) { AtomicBoolean b = (AtomicBoolean) from; return b.get() ? new AtomicInteger(1) : new AtomicInteger (0); } + static AtomicLong toAtomicLong(Object from, Converter converter, ConverterOptions options) { AtomicBoolean b = (AtomicBoolean) from; return b.get() ? new AtomicLong(1) : new AtomicLong(0); diff --git a/src/main/java/com/cedarsoftware/util/convert/BooleanConversion.java b/src/main/java/com/cedarsoftware/util/convert/BooleanConversions.java similarity index 95% rename from src/main/java/com/cedarsoftware/util/convert/BooleanConversion.java rename to src/main/java/com/cedarsoftware/util/convert/BooleanConversions.java index 44b6b6fa..62a348af 100644 --- a/src/main/java/com/cedarsoftware/util/convert/BooleanConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/BooleanConversions.java @@ -24,7 +24,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -public class BooleanConversion { +public final class BooleanConversions { + + private BooleanConversions() { + } + static Byte toByte(Object from, Converter converter, ConverterOptions options) { Boolean b = (Boolean) from; return b ? CommonValues.BYTE_ONE : CommonValues.BYTE_ZERO; @@ -81,6 +85,6 @@ static Double toDouble(Object from, Converter converter, ConverterOptions option static char toCharacter(Object from, Converter converter, ConverterOptions options) { Boolean b = (Boolean) from; - return b ? CommonValues.CHARACTER_ONE : CommonValues.CHARACTER_ZERO; + return b ? options.trueChar() : options.falseChar(); } } diff --git a/src/main/java/com/cedarsoftware/util/convert/CalendarConversion.java b/src/main/java/com/cedarsoftware/util/convert/CalendarConversions.java similarity index 89% rename from src/main/java/com/cedarsoftware/util/convert/CalendarConversion.java rename to src/main/java/com/cedarsoftware/util/convert/CalendarConversions.java index 7f72de01..29e7c803 100644 --- a/src/main/java/com/cedarsoftware/util/convert/CalendarConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/CalendarConversions.java @@ -6,13 +6,14 @@ 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.GregorianCalendar; import java.util.concurrent.atomic.AtomicLong; -public class CalendarConversion { +public class CalendarConversions { static Date toDate(Object fromInstance) { return ((Calendar)fromInstance).getTime(); @@ -34,11 +35,15 @@ static ZonedDateTime toZonedDateTime(Object fromInstance, Converter converter, C return toZonedDateTime(fromInstance, options); } - static Long toLong(Object fromInstance, Converter converter, ConverterOptions options) { return toLong(fromInstance); } + static double toDouble(Object fromInstance, Converter converter, ConverterOptions options) { + return (double)toLong(fromInstance); + } + + static Date toDate(Object fromInstance, Converter converter, ConverterOptions options) { return toDate(fromInstance); } @@ -67,6 +72,10 @@ static LocalDate toLocalDate(Object fromInstance, Converter converter, Converter return toZonedDateTime(fromInstance, options).toLocalDate(); } + static LocalTime toLocalTime(Object fromInstance, Converter converter, ConverterOptions options) { + return toZonedDateTime(fromInstance, options).toLocalTime(); + } + static BigDecimal toBigDecimal(Object fromInstance, Converter converter, ConverterOptions options) { return BigDecimal.valueOf(toLong(fromInstance)); } @@ -87,8 +96,4 @@ static Calendar create(long epochMilli, ConverterOptions options) { 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/CharacterConversions.java similarity index 90% rename from src/main/java/com/cedarsoftware/util/convert/CharacterConversion.java rename to src/main/java/com/cedarsoftware/util/convert/CharacterConversions.java index 25b5aecd..ec2d2a73 100644 --- a/src/main/java/com/cedarsoftware/util/convert/CharacterConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/CharacterConversions.java @@ -1,24 +1,19 @@ 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 { +public class CharacterConversions { - private CharacterConversion() { + private CharacterConversions() { } static boolean toBoolean(Object from) { char c = (char) from; - return (c == 1) || (c == 't') || (c == 'T') || (c == '1'); + return (c == 1) || (c == 't') || (c == 'T') || (c == '1') || (c == 'y') || (c == 'Y'); } diff --git a/src/main/java/com/cedarsoftware/util/convert/Converter.java b/src/main/java/com/cedarsoftware/util/convert/Converter.java index 5c4ea206..79d632a7 100644 --- a/src/main/java/com/cedarsoftware/util/convert/Converter.java +++ b/src/main/java/com/cedarsoftware/util/convert/Converter.java @@ -36,6 +36,7 @@ import com.cedarsoftware.util.ClassUtilities; import com.cedarsoftware.util.CollectionUtilities; import com.cedarsoftware.util.DateUtilities; +import com.cedarsoftware.util.StringUtilities; /** * Instance conversion utility. Convert from primitive to other primitives, plus support for Number, Date, @@ -108,393 +109,361 @@ private static void buildPrimitiveWrappers() { private static void buildFactoryConversions() { // Byte/byte Conversions supported - DEFAULT_FACTORY.put(pair(Void.class, byte.class), NumberConversion::toByteZero); - DEFAULT_FACTORY.put(pair(Void.class, Byte.class), VoidConversion::toNull); + DEFAULT_FACTORY.put(pair(Void.class, byte.class), NumberConversions::toByteZero); + DEFAULT_FACTORY.put(pair(Void.class, Byte.class), VoidConversions::toNull); DEFAULT_FACTORY.put(pair(Byte.class, Byte.class), Converter::identity); - DEFAULT_FACTORY.put(pair(Short.class, Byte.class), NumberConversion::toByte); - DEFAULT_FACTORY.put(pair(Integer.class, Byte.class), NumberConversion::toByte); - DEFAULT_FACTORY.put(pair(Long.class, Byte.class), NumberConversion::toByte); - 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), 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); - DEFAULT_FACTORY.put(pair(AtomicLong.class, Byte.class), NumberConversion::toByte); - DEFAULT_FACTORY.put(pair(BigInteger.class, Byte.class), NumberConversion::toByte); - DEFAULT_FACTORY.put(pair(BigDecimal.class, Byte.class), NumberConversion::toByte); - DEFAULT_FACTORY.put(pair(Number.class, Byte.class), NumberConversion::toByte); - DEFAULT_FACTORY.put(pair(Map.class, Byte.class), MapConversion::toByte); - DEFAULT_FACTORY.put(pair(String.class, Byte.class), StringConversion::toByte); + DEFAULT_FACTORY.put(pair(Short.class, Byte.class), NumberConversions::toByte); + DEFAULT_FACTORY.put(pair(Integer.class, Byte.class), NumberConversions::toByte); + DEFAULT_FACTORY.put(pair(Long.class, Byte.class), NumberConversions::toByte); + DEFAULT_FACTORY.put(pair(Float.class, Byte.class), NumberConversions::toByte); + DEFAULT_FACTORY.put(pair(Double.class, Byte.class), NumberConversions::toByte); + DEFAULT_FACTORY.put(pair(Boolean.class, Byte.class), BooleanConversions::toByte); + DEFAULT_FACTORY.put(pair(Character.class, Byte.class), CharacterConversions::toByte); + DEFAULT_FACTORY.put(pair(Calendar.class, Byte.class), NumberConversions::toByte); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Byte.class), AtomicBooleanConversions::toByte); + DEFAULT_FACTORY.put(pair(AtomicInteger.class, Byte.class), NumberConversions::toByte); + DEFAULT_FACTORY.put(pair(AtomicLong.class, Byte.class), NumberConversions::toByte); + DEFAULT_FACTORY.put(pair(BigInteger.class, Byte.class), NumberConversions::toByte); + DEFAULT_FACTORY.put(pair(BigDecimal.class, Byte.class), NumberConversions::toByte); + DEFAULT_FACTORY.put(pair(Number.class, Byte.class), NumberConversions::toByte); + DEFAULT_FACTORY.put(pair(Map.class, Byte.class), MapConversions::toByte); + DEFAULT_FACTORY.put(pair(String.class, Byte.class), StringConversions::toByte); // Short/short conversions supported - DEFAULT_FACTORY.put(pair(Void.class, short.class), NumberConversion::toShortZero); - DEFAULT_FACTORY.put(pair(Void.class, Short.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Byte.class, Short.class), NumberConversion::toShort); + DEFAULT_FACTORY.put(pair(Void.class, short.class), NumberConversions::toShortZero); + DEFAULT_FACTORY.put(pair(Void.class, Short.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Byte.class, Short.class), NumberConversions::toShort); DEFAULT_FACTORY.put(pair(Short.class, Short.class), Converter::identity); - DEFAULT_FACTORY.put(pair(Integer.class, Short.class), NumberConversion::toShort); - DEFAULT_FACTORY.put(pair(Long.class, Short.class), NumberConversion::toShort); - 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), 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); - DEFAULT_FACTORY.put(pair(BigInteger.class, Short.class), NumberConversion::toShort); - DEFAULT_FACTORY.put(pair(BigDecimal.class, Short.class), NumberConversion::toShort); - DEFAULT_FACTORY.put(pair(LocalDate.class, Short.class), (fromInstance, converter, options) -> ((LocalDate) fromInstance).toEpochDay()); - DEFAULT_FACTORY.put(pair(Number.class, Short.class), NumberConversion::toShort); - DEFAULT_FACTORY.put(pair(Map.class, Short.class), (fromInstance, converter, options) -> converter.fromValueMap((Map) fromInstance, short.class, null, options)); - DEFAULT_FACTORY.put(pair(String.class, Short.class), StringConversion::toShort); + DEFAULT_FACTORY.put(pair(Integer.class, Short.class), NumberConversions::toShort); + DEFAULT_FACTORY.put(pair(Long.class, Short.class), NumberConversions::toShort); + DEFAULT_FACTORY.put(pair(Float.class, Short.class), NumberConversions::toShort); + DEFAULT_FACTORY.put(pair(Double.class, Short.class), NumberConversions::toShort); + DEFAULT_FACTORY.put(pair(Boolean.class, Short.class), BooleanConversions::toShort); + DEFAULT_FACTORY.put(pair(Character.class, Short.class), CharacterConversions::toShort); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Short.class), AtomicBooleanConversions::toShort); + DEFAULT_FACTORY.put(pair(AtomicInteger.class, Short.class), NumberConversions::toShort); + DEFAULT_FACTORY.put(pair(AtomicLong.class, Short.class), NumberConversions::toShort); + DEFAULT_FACTORY.put(pair(BigInteger.class, Short.class), NumberConversions::toShort); + DEFAULT_FACTORY.put(pair(BigDecimal.class, Short.class), NumberConversions::toShort); + DEFAULT_FACTORY.put(pair(Number.class, Short.class), NumberConversions::toShort); + DEFAULT_FACTORY.put(pair(Map.class, Short.class), MapConversions::toShort); + DEFAULT_FACTORY.put(pair(String.class, Short.class), StringConversions::toShort); // Integer/int conversions supported - DEFAULT_FACTORY.put(pair(Void.class, int.class), NumberConversion::toIntZero); - DEFAULT_FACTORY.put(pair(Void.class, Integer.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Byte.class, Integer.class), NumberConversion::toInt); - DEFAULT_FACTORY.put(pair(Short.class, Integer.class), NumberConversion::toInt); + DEFAULT_FACTORY.put(pair(Void.class, int.class), NumberConversions::toIntZero); + DEFAULT_FACTORY.put(pair(Void.class, Integer.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Byte.class, Integer.class), NumberConversions::toInt); + DEFAULT_FACTORY.put(pair(Short.class, Integer.class), NumberConversions::toInt); DEFAULT_FACTORY.put(pair(Integer.class, Integer.class), Converter::identity); - DEFAULT_FACTORY.put(pair(Long.class, Integer.class), NumberConversion::toInt); - 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), 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); - DEFAULT_FACTORY.put(pair(BigInteger.class, Integer.class), NumberConversion::toInt); - DEFAULT_FACTORY.put(pair(BigDecimal.class, Integer.class), NumberConversion::toInt); - DEFAULT_FACTORY.put(pair(LocalDate.class, Integer.class), (fromInstance, converter, options) -> (int) ((LocalDate) fromInstance).toEpochDay()); - DEFAULT_FACTORY.put(pair(Number.class, Integer.class), NumberConversion::toInt); - DEFAULT_FACTORY.put(pair(Map.class, Integer.class), MapConversion::toInt); - DEFAULT_FACTORY.put(pair(String.class, Integer.class), StringConversion::toInt); + DEFAULT_FACTORY.put(pair(Long.class, Integer.class), NumberConversions::toInt); + DEFAULT_FACTORY.put(pair(Float.class, Integer.class), NumberConversions::toInt); + DEFAULT_FACTORY.put(pair(Double.class, Integer.class), NumberConversions::toInt); + DEFAULT_FACTORY.put(pair(Boolean.class, Integer.class), BooleanConversions::toInteger); + DEFAULT_FACTORY.put(pair(Character.class, Integer.class), CharacterConversions::toInt); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Integer.class), AtomicBooleanConversions::toInteger); + DEFAULT_FACTORY.put(pair(AtomicInteger.class, Integer.class), NumberConversions::toInt); + DEFAULT_FACTORY.put(pair(AtomicLong.class, Integer.class), NumberConversions::toInt); + DEFAULT_FACTORY.put(pair(BigInteger.class, Integer.class), NumberConversions::toInt); + DEFAULT_FACTORY.put(pair(BigDecimal.class, Integer.class), NumberConversions::toInt); + DEFAULT_FACTORY.put(pair(Number.class, Integer.class), NumberConversions::toInt); + DEFAULT_FACTORY.put(pair(Map.class, Integer.class), MapConversions::toInt); + DEFAULT_FACTORY.put(pair(String.class, Integer.class), StringConversions::toInt); // Long/long conversions supported - DEFAULT_FACTORY.put(pair(Void.class, long.class), NumberConversion::toLongZero); - DEFAULT_FACTORY.put(pair(Void.class, Long.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Byte.class, Long.class), NumberConversion::toLong); - DEFAULT_FACTORY.put(pair(Short.class, Long.class), NumberConversion::toLong); - DEFAULT_FACTORY.put(pair(Integer.class, Long.class), NumberConversion::toLong); + DEFAULT_FACTORY.put(pair(Void.class, long.class), NumberConversions::toLongZero); + DEFAULT_FACTORY.put(pair(Void.class, Long.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Byte.class, Long.class), NumberConversions::toLong); + DEFAULT_FACTORY.put(pair(Short.class, Long.class), NumberConversions::toLong); + DEFAULT_FACTORY.put(pair(Integer.class, Long.class), NumberConversions::toLong); DEFAULT_FACTORY.put(pair(Long.class, Long.class), Converter::identity); - 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), 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), 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); + DEFAULT_FACTORY.put(pair(Float.class, Long.class), NumberConversions::toLong); + DEFAULT_FACTORY.put(pair(Double.class, Long.class), NumberConversions::toLong); + DEFAULT_FACTORY.put(pair(Boolean.class, Long.class), BooleanConversions::toLong); + DEFAULT_FACTORY.put(pair(Character.class, Long.class), CharacterConversions::toLong); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Long.class), AtomicBooleanConversions::toLong); + DEFAULT_FACTORY.put(pair(AtomicInteger.class, Long.class), NumberConversions::toLong); + DEFAULT_FACTORY.put(pair(AtomicLong.class, Long.class), NumberConversions::toLong); + DEFAULT_FACTORY.put(pair(BigInteger.class, Long.class), NumberConversions::toLong); + DEFAULT_FACTORY.put(pair(BigDecimal.class, Long.class), NumberConversions::toLong); + DEFAULT_FACTORY.put(pair(Date.class, Long.class), DateConversions::toLong); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, Long.class), DateConversions::toLong); + DEFAULT_FACTORY.put(pair(Timestamp.class, Long.class), DateConversions::toLong); + DEFAULT_FACTORY.put(pair(Instant.class, Long.class), InstantConversions::toLong); + DEFAULT_FACTORY.put(pair(LocalDate.class, Long.class), LocalDateConversions::toLong); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, Long.class), LocalDateTimeConversions::toLong); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, Long.class), ZonedDateTimeConversions::toLong); + DEFAULT_FACTORY.put(pair(Calendar.class, Long.class), CalendarConversions::toLong); + DEFAULT_FACTORY.put(pair(Number.class, Long.class), NumberConversions::toLong); + DEFAULT_FACTORY.put(pair(Map.class, Long.class), MapConversions::toLong); + DEFAULT_FACTORY.put(pair(String.class, Long.class), StringConversions::toLong); // Float/float conversions supported - DEFAULT_FACTORY.put(pair(Void.class, float.class), NumberConversion::toFloatZero); - DEFAULT_FACTORY.put(pair(Void.class, Float.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Byte.class, Float.class), NumberConversion::toFloat); - DEFAULT_FACTORY.put(pair(Short.class, Float.class), NumberConversion::toFloat); - DEFAULT_FACTORY.put(pair(Integer.class, Float.class), NumberConversion::toFloat); - DEFAULT_FACTORY.put(pair(Long.class, Float.class), NumberConversion::toFloat); + DEFAULT_FACTORY.put(pair(Void.class, float.class), NumberConversions::toFloatZero); + DEFAULT_FACTORY.put(pair(Void.class, Float.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Byte.class, Float.class), NumberConversions::toFloat); + DEFAULT_FACTORY.put(pair(Short.class, Float.class), NumberConversions::toFloat); + DEFAULT_FACTORY.put(pair(Integer.class, Float.class), NumberConversions::toFloat); + DEFAULT_FACTORY.put(pair(Long.class, Float.class), NumberConversions::toFloat); DEFAULT_FACTORY.put(pair(Float.class, Float.class), Converter::identity); - 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(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); - DEFAULT_FACTORY.put(pair(BigInteger.class, Float.class), NumberConversion::toFloat); - DEFAULT_FACTORY.put(pair(BigDecimal.class, Float.class), NumberConversion::toFloat); - DEFAULT_FACTORY.put(pair(Number.class, Float.class), NumberConversion::toFloat); - DEFAULT_FACTORY.put(pair(Map.class, Float.class), MapConversion::toFloat); - DEFAULT_FACTORY.put(pair(String.class, Float.class), StringConversion::toFloat); + DEFAULT_FACTORY.put(pair(Double.class, Float.class), NumberConversions::toFloat); + DEFAULT_FACTORY.put(pair(Boolean.class, Float.class), BooleanConversions::toFloat); + DEFAULT_FACTORY.put(pair(Character.class, Float.class), CharacterConversions::toFloat); + DEFAULT_FACTORY.put(pair(Instant.class, Float.class), InstantConversions::toFloat); + DEFAULT_FACTORY.put(pair(LocalDate.class, Float.class), LocalDateConversions::toFloat); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Float.class), AtomicBooleanConversions::toFloat); + DEFAULT_FACTORY.put(pair(AtomicInteger.class, Float.class), NumberConversions::toFloat); + DEFAULT_FACTORY.put(pair(AtomicLong.class, Float.class), NumberConversions::toFloat); + DEFAULT_FACTORY.put(pair(BigInteger.class, Float.class), NumberConversions::toFloat); + DEFAULT_FACTORY.put(pair(BigDecimal.class, Float.class), NumberConversions::toFloat); + DEFAULT_FACTORY.put(pair(Number.class, Float.class), NumberConversions::toFloat); + DEFAULT_FACTORY.put(pair(Map.class, Float.class), MapConversions::toFloat); + DEFAULT_FACTORY.put(pair(String.class, Float.class), StringConversions::toFloat); // Double/double conversions supported - 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); - DEFAULT_FACTORY.put(pair(Integer.class, Double.class), NumberConversion::toDouble); - DEFAULT_FACTORY.put(pair(Long.class, Double.class), NumberConversion::toDouble); - DEFAULT_FACTORY.put(pair(Float.class, Double.class), NumberConversion::toDouble); + DEFAULT_FACTORY.put(pair(Void.class, double.class), NumberConversions::toDoubleZero); + DEFAULT_FACTORY.put(pair(Void.class, Double.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Byte.class, Double.class), NumberConversions::toDouble); + DEFAULT_FACTORY.put(pair(Short.class, Double.class), NumberConversions::toDouble); + DEFAULT_FACTORY.put(pair(Integer.class, Double.class), NumberConversions::toDouble); + DEFAULT_FACTORY.put(pair(Long.class, Double.class), NumberConversions::toDouble); + DEFAULT_FACTORY.put(pair(Float.class, Double.class), NumberConversions::toDouble); 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(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); - DEFAULT_FACTORY.put(pair(BigInteger.class, Double.class), NumberConversion::toDouble); - DEFAULT_FACTORY.put(pair(BigDecimal.class, Double.class), NumberConversion::toDouble); - DEFAULT_FACTORY.put(pair(Calendar.class, Double.class), (fromInstance, converter, options) -> (double) ((Calendar) fromInstance).getTime().getTime()); - DEFAULT_FACTORY.put(pair(Number.class, Double.class), NumberConversion::toDouble); - DEFAULT_FACTORY.put(pair(Map.class, Double.class), MapConversion::toDouble); - DEFAULT_FACTORY.put(pair(String.class, Double.class), StringConversion::toDouble); + DEFAULT_FACTORY.put(pair(Boolean.class, Double.class), BooleanConversions::toDouble); + DEFAULT_FACTORY.put(pair(Character.class, Double.class), CharacterConversions::toDouble); + DEFAULT_FACTORY.put(pair(Instant.class, Double.class), InstantConversions::toDouble); + DEFAULT_FACTORY.put(pair(LocalDate.class, Double.class), LocalDateConversions::toDouble); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, Double.class), LocalDateTimeConversions::toLong); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, Double.class), ZonedDateTimeConversions::toLong); + DEFAULT_FACTORY.put(pair(Date.class, Double.class), DateConversions::toLong); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, Double.class), DateConversions::toLong); + DEFAULT_FACTORY.put(pair(Timestamp.class, Double.class), DateConversions::toLong); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Double.class), AtomicBooleanConversions::toDouble); + DEFAULT_FACTORY.put(pair(AtomicInteger.class, Double.class), NumberConversions::toDouble); + DEFAULT_FACTORY.put(pair(AtomicLong.class, Double.class), NumberConversions::toDouble); + DEFAULT_FACTORY.put(pair(BigInteger.class, Double.class), NumberConversions::toDouble); + DEFAULT_FACTORY.put(pair(BigDecimal.class, Double.class), NumberConversions::toDouble); + DEFAULT_FACTORY.put(pair(Calendar.class, Double.class), CalendarConversions::toDouble); + DEFAULT_FACTORY.put(pair(Number.class, Double.class), NumberConversions::toDouble); + DEFAULT_FACTORY.put(pair(Map.class, Double.class), MapConversions::toDouble); + DEFAULT_FACTORY.put(pair(String.class, Double.class), StringConversions::toDouble); // Boolean/boolean conversions supported - DEFAULT_FACTORY.put(pair(Void.class, boolean.class), VoidConversion::toBoolean); - DEFAULT_FACTORY.put(pair(Void.class, Boolean.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Byte.class, Boolean.class), NumberConversion::isIntTypeNotZero); - DEFAULT_FACTORY.put(pair(Short.class, Boolean.class), NumberConversion::isIntTypeNotZero); - DEFAULT_FACTORY.put(pair(Integer.class, Boolean.class), NumberConversion::isIntTypeNotZero); - DEFAULT_FACTORY.put(pair(Long.class, Boolean.class), NumberConversion::isIntTypeNotZero); - DEFAULT_FACTORY.put(pair(Float.class, Boolean.class), NumberConversion::isFloatTypeNotZero); - DEFAULT_FACTORY.put(pair(Double.class, Boolean.class), NumberConversion::isFloatTypeNotZero); + DEFAULT_FACTORY.put(pair(Void.class, boolean.class), VoidConversions::toBoolean); + DEFAULT_FACTORY.put(pair(Void.class, Boolean.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Byte.class, Boolean.class), NumberConversions::isIntTypeNotZero); + DEFAULT_FACTORY.put(pair(Short.class, Boolean.class), NumberConversions::isIntTypeNotZero); + DEFAULT_FACTORY.put(pair(Integer.class, Boolean.class), NumberConversions::isIntTypeNotZero); + DEFAULT_FACTORY.put(pair(Long.class, Boolean.class), NumberConversions::isIntTypeNotZero); + DEFAULT_FACTORY.put(pair(Float.class, Boolean.class), NumberConversions::isFloatTypeNotZero); + DEFAULT_FACTORY.put(pair(Double.class, Boolean.class), NumberConversions::isFloatTypeNotZero); DEFAULT_FACTORY.put(pair(Boolean.class, Boolean.class), Converter::identity); - DEFAULT_FACTORY.put(pair(Character.class, Boolean.class), CharacterConversion::toBoolean); - DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Boolean.class), AtomicBooleanConversion::toBoolean); - DEFAULT_FACTORY.put(pair(AtomicInteger.class, Boolean.class), NumberConversion::isIntTypeNotZero); - DEFAULT_FACTORY.put(pair(AtomicLong.class, Boolean.class), NumberConversion::isIntTypeNotZero); - DEFAULT_FACTORY.put(pair(BigInteger.class, Boolean.class), NumberConversion::isBigIntegerNotZero); - DEFAULT_FACTORY.put(pair(BigDecimal.class, Boolean.class), NumberConversion::isBigDecimalNotZero); - DEFAULT_FACTORY.put(pair(Number.class, Boolean.class), NumberConversion::isIntTypeNotZero); - DEFAULT_FACTORY.put(pair(Map.class, Boolean.class), MapConversion::toBoolean); - DEFAULT_FACTORY.put(pair(String.class, Boolean.class), StringConversion::toBoolean); + DEFAULT_FACTORY.put(pair(Character.class, Boolean.class), CharacterConversions::toBoolean); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Boolean.class), AtomicBooleanConversions::toBoolean); + DEFAULT_FACTORY.put(pair(AtomicInteger.class, Boolean.class), NumberConversions::isIntTypeNotZero); + DEFAULT_FACTORY.put(pair(AtomicLong.class, Boolean.class), NumberConversions::isIntTypeNotZero); + DEFAULT_FACTORY.put(pair(BigInteger.class, Boolean.class), NumberConversions::isBigIntegerNotZero); + DEFAULT_FACTORY.put(pair(BigDecimal.class, Boolean.class), NumberConversions::isBigDecimalNotZero); + DEFAULT_FACTORY.put(pair(Number.class, Boolean.class), NumberConversions::isIntTypeNotZero); + DEFAULT_FACTORY.put(pair(Map.class, Boolean.class), MapConversions::toBoolean); + DEFAULT_FACTORY.put(pair(String.class, Boolean.class), StringConversions::toBoolean); // Character/chat conversions supported - DEFAULT_FACTORY.put(pair(Void.class, char.class), VoidConversion::toChar); - DEFAULT_FACTORY.put(pair(Void.class, Character.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Byte.class, Character.class), NumberConversion::toCharacter); - DEFAULT_FACTORY.put(pair(Short.class, Character.class), NumberConversion::toCharacter); - DEFAULT_FACTORY.put(pair(Integer.class, Character.class), NumberConversion::toCharacter); - DEFAULT_FACTORY.put(pair(Long.class, Character.class), NumberConversion::toCharacter); - DEFAULT_FACTORY.put(pair(Float.class, Character.class), NumberConversion::toCharacter); - DEFAULT_FACTORY.put(pair(Double.class, Character.class), NumberConversion::toCharacter); - DEFAULT_FACTORY.put(pair(Boolean.class, Character.class), BooleanConversion::toCharacter); + DEFAULT_FACTORY.put(pair(Void.class, char.class), VoidConversions::toChar); + DEFAULT_FACTORY.put(pair(Void.class, Character.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Byte.class, Character.class), NumberConversions::toCharacter); + DEFAULT_FACTORY.put(pair(Short.class, Character.class), NumberConversions::toCharacter); + DEFAULT_FACTORY.put(pair(Integer.class, Character.class), NumberConversions::toCharacter); + DEFAULT_FACTORY.put(pair(Long.class, Character.class), NumberConversions::toCharacter); + DEFAULT_FACTORY.put(pair(Float.class, Character.class), NumberConversions::toCharacter); + DEFAULT_FACTORY.put(pair(Double.class, Character.class), NumberConversions::toCharacter); + DEFAULT_FACTORY.put(pair(Boolean.class, Character.class), BooleanConversions::toCharacter); DEFAULT_FACTORY.put(pair(Character.class, Character.class), Converter::identity); - DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Character.class), AtomicBooleanConversion::toCharacter); - DEFAULT_FACTORY.put(pair(AtomicInteger.class, Character.class), NumberConversion::toCharacter); - DEFAULT_FACTORY.put(pair(AtomicLong.class, Character.class), NumberConversion::toCharacter); - DEFAULT_FACTORY.put(pair(BigInteger.class, Character.class), NumberConversion::toCharacter); - DEFAULT_FACTORY.put(pair(BigDecimal.class, Character.class), NumberConversion::toCharacter); - DEFAULT_FACTORY.put(pair(Number.class, Character.class), NumberConversion::toCharacter); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, Character.class), AtomicBooleanConversions::toCharacter); + DEFAULT_FACTORY.put(pair(AtomicInteger.class, Character.class), NumberConversions::toCharacter); + DEFAULT_FACTORY.put(pair(AtomicLong.class, Character.class), NumberConversions::toCharacter); + DEFAULT_FACTORY.put(pair(BigInteger.class, Character.class), NumberConversions::toCharacter); + DEFAULT_FACTORY.put(pair(BigDecimal.class, Character.class), NumberConversions::toCharacter); + DEFAULT_FACTORY.put(pair(Number.class, Character.class), NumberConversions::toCharacter); DEFAULT_FACTORY.put(pair(Map.class, Character.class), (fromInstance, converter, options) -> converter.fromValueMap((Map) fromInstance, char.class, null, options)); - DEFAULT_FACTORY.put(pair(String.class, Character.class), StringConversion::toCharacter); + DEFAULT_FACTORY.put(pair(String.class, Character.class), StringConversions::toCharacter); // BigInteger versions supported - DEFAULT_FACTORY.put(pair(Void.class, BigInteger.class), VoidConversion::toNull); - 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), BooleanConversion::toBigInteger); - DEFAULT_FACTORY.put(pair(Character.class, BigInteger.class), CharacterConversion::toBigInteger); + DEFAULT_FACTORY.put(pair(Void.class, BigInteger.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Byte.class, BigInteger.class), NumberConversions::integerTypeToBigInteger); + DEFAULT_FACTORY.put(pair(Short.class, BigInteger.class), NumberConversions::integerTypeToBigInteger); + DEFAULT_FACTORY.put(pair(Integer.class, BigInteger.class), NumberConversions::integerTypeToBigInteger); + DEFAULT_FACTORY.put(pair(Long.class, BigInteger.class), NumberConversions::integerTypeToBigInteger); + DEFAULT_FACTORY.put(pair(Float.class, BigInteger.class), NumberConversions::floatingPointToBigInteger); + DEFAULT_FACTORY.put(pair(Double.class, BigInteger.class), NumberConversions::floatingPointToBigInteger); + DEFAULT_FACTORY.put(pair(Boolean.class, BigInteger.class), BooleanConversions::toBigInteger); + DEFAULT_FACTORY.put(pair(Character.class, BigInteger.class), CharacterConversions::toBigInteger); DEFAULT_FACTORY.put(pair(BigInteger.class, BigInteger.class), Converter::identity); - 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()); - BigInteger leastSignificant = BigInteger.valueOf(uuid.getLeastSignificantBits()); - // Shift the most significant bits to the left and add the least significant bits - return mostSignificant.shiftLeft(64).add(leastSignificant); - }); - DEFAULT_FACTORY.put(pair(Calendar.class, BigInteger.class), CalendarConversion::toBigInteger); - DEFAULT_FACTORY.put(pair(Number.class, BigInteger.class), (fromInstance, converter, options) -> new BigInteger(fromInstance.toString())); - DEFAULT_FACTORY.put(pair(Map.class, BigInteger.class), MapConversion::toBigInteger); - DEFAULT_FACTORY.put(pair(String.class, BigInteger.class), StringConversion::toBigInteger); - - + DEFAULT_FACTORY.put(pair(BigDecimal.class, BigInteger.class), NumberConversions::bigDecimalToBigInteger); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, BigInteger.class), AtomicBooleanConversions::toBigInteger); + DEFAULT_FACTORY.put(pair(AtomicInteger.class, BigInteger.class), NumberConversions::integerTypeToBigInteger); + DEFAULT_FACTORY.put(pair(AtomicLong.class, BigInteger.class), NumberConversions::integerTypeToBigInteger); + DEFAULT_FACTORY.put(pair(Date.class, BigInteger.class), DateConversions::toBigInteger); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, BigInteger.class), DateConversions::toBigInteger); + DEFAULT_FACTORY.put(pair(Timestamp.class, BigInteger.class), DateConversions::toBigInteger); + DEFAULT_FACTORY.put(pair(Instant.class, BigInteger.class), InstantConversions::toBigInteger); + DEFAULT_FACTORY.put(pair(LocalDate.class, BigInteger.class), LocalDateConversions::toBigInteger); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, BigInteger.class), LocalDateTimeConversions::toBigInteger); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, BigInteger.class), ZonedDateTimeConversions::toBigInteger); + DEFAULT_FACTORY.put(pair(UUID.class, BigInteger.class), UUIDConversions::toBigInteger); + DEFAULT_FACTORY.put(pair(Calendar.class, BigInteger.class), CalendarConversions::toBigInteger); + DEFAULT_FACTORY.put(pair(Number.class, BigInteger.class), NumberConversions::toBigInteger); + DEFAULT_FACTORY.put(pair(Map.class, BigInteger.class), MapConversions::toBigInteger); + DEFAULT_FACTORY.put(pair(String.class, BigInteger.class), StringConversions::toBigInteger); // BigDecimal conversions supported - DEFAULT_FACTORY.put(pair(Void.class, BigDecimal.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Byte.class, BigDecimal.class), NumberConversion::integerTypeToBigDecimal); - DEFAULT_FACTORY.put(pair(Short.class, BigDecimal.class), NumberConversion::integerTypeToBigDecimal); - DEFAULT_FACTORY.put(pair(Integer.class, BigDecimal.class), NumberConversion::integerTypeToBigDecimal); - DEFAULT_FACTORY.put(pair(Long.class, BigDecimal.class), NumberConversion::integerTypeToBigDecimal); - DEFAULT_FACTORY.put(pair(Float.class, BigDecimal.class), NumberConversion::floatingPointToBigDecimal); - DEFAULT_FACTORY.put(pair(Double.class, BigDecimal.class), NumberConversion::floatingPointToBigDecimal); - DEFAULT_FACTORY.put(pair(Boolean.class, BigDecimal.class), BooleanConversion::toBigDecimal); - DEFAULT_FACTORY.put(pair(Character.class, BigDecimal.class), CharacterConversion::toBigDecimal); + DEFAULT_FACTORY.put(pair(Void.class, BigDecimal.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Byte.class, BigDecimal.class), NumberConversions::integerTypeToBigDecimal); + DEFAULT_FACTORY.put(pair(Short.class, BigDecimal.class), NumberConversions::integerTypeToBigDecimal); + DEFAULT_FACTORY.put(pair(Integer.class, BigDecimal.class), NumberConversions::integerTypeToBigDecimal); + DEFAULT_FACTORY.put(pair(Long.class, BigDecimal.class), NumberConversions::integerTypeToBigDecimal); + DEFAULT_FACTORY.put(pair(Float.class, BigDecimal.class), NumberConversions::floatingPointToBigDecimal); + DEFAULT_FACTORY.put(pair(Double.class, BigDecimal.class), NumberConversions::floatingPointToBigDecimal); + DEFAULT_FACTORY.put(pair(Boolean.class, BigDecimal.class), BooleanConversions::toBigDecimal); + DEFAULT_FACTORY.put(pair(Character.class, BigDecimal.class), CharacterConversions::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); - DEFAULT_FACTORY.put(pair(AtomicInteger.class, BigDecimal.class), NumberConversion::integerTypeToBigDecimal); - DEFAULT_FACTORY.put(pair(AtomicLong.class, BigDecimal.class), NumberConversion::integerTypeToBigDecimal); - DEFAULT_FACTORY.put(pair(Date.class, BigDecimal.class), DateConversion::toBigDecimal); - DEFAULT_FACTORY.put(pair(java.sql.Date.class, BigDecimal.class), DateConversion::toBigDecimal); - DEFAULT_FACTORY.put(pair(Timestamp.class, BigDecimal.class), DateConversion::toBigDecimal); - DEFAULT_FACTORY.put(pair(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()); - BigInteger leastSignificant = BigInteger.valueOf(uuid.getLeastSignificantBits()); - // Shift the most significant bits to the left and add the least significant bits - return new BigDecimal(mostSignificant.shiftLeft(64).add(leastSignificant)); - }); - DEFAULT_FACTORY.put(pair(Calendar.class, BigDecimal.class), CalendarConversion::toBigDecimal); - DEFAULT_FACTORY.put(pair(Number.class, BigDecimal.class), (fromInstance, converter, options) -> new BigDecimal(fromInstance.toString())); - DEFAULT_FACTORY.put(pair(Map.class, BigDecimal.class), MapConversion::toBigDecimal); - DEFAULT_FACTORY.put(pair(String.class, BigDecimal.class), StringConversion::toBigDecimal); + DEFAULT_FACTORY.put(pair(BigInteger.class, BigDecimal.class), NumberConversions::bigIntegerToBigDecimal); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, BigDecimal.class), AtomicBooleanConversions::toBigDecimal); + DEFAULT_FACTORY.put(pair(AtomicInteger.class, BigDecimal.class), NumberConversions::integerTypeToBigDecimal); + DEFAULT_FACTORY.put(pair(AtomicLong.class, BigDecimal.class), NumberConversions::integerTypeToBigDecimal); + DEFAULT_FACTORY.put(pair(Date.class, BigDecimal.class), DateConversions::toBigDecimal); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, BigDecimal.class), DateConversions::toBigDecimal); + DEFAULT_FACTORY.put(pair(Timestamp.class, BigDecimal.class), DateConversions::toBigDecimal); + DEFAULT_FACTORY.put(pair(Instant.class, BigDecimal.class), InstantConversions::toBigDecimal); + DEFAULT_FACTORY.put(pair(LocalDate.class, BigDecimal.class), LocalDateConversions::toBigDecimal); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, BigDecimal.class), LocalDateTimeConversions::toBigDecimal); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, BigDecimal.class), ZonedDateTimeConversions::toBigDecimal); + DEFAULT_FACTORY.put(pair(UUID.class, BigDecimal.class), UUIDConversions::toBigDecimal); + DEFAULT_FACTORY.put(pair(Calendar.class, BigDecimal.class), CalendarConversions::toBigDecimal); + DEFAULT_FACTORY.put(pair(Number.class, BigDecimal.class), NumberConversions::bigDecimalToBigDecimal); + DEFAULT_FACTORY.put(pair(Map.class, BigDecimal.class), MapConversions::toBigDecimal); + DEFAULT_FACTORY.put(pair(String.class, BigDecimal.class), StringConversions::toBigDecimal); // AtomicBoolean conversions supported - DEFAULT_FACTORY.put(pair(Void.class, AtomicBoolean.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Byte.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); - DEFAULT_FACTORY.put(pair(Short.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); - DEFAULT_FACTORY.put(pair(Integer.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); - DEFAULT_FACTORY.put(pair(Long.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); - DEFAULT_FACTORY.put(pair(Float.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); - DEFAULT_FACTORY.put(pair(Double.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); - DEFAULT_FACTORY.put(pair(Boolean.class, AtomicBoolean.class), BooleanConversion::toAtomicBoolean); - 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 - DEFAULT_FACTORY.put(pair(AtomicInteger.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); - DEFAULT_FACTORY.put(pair(AtomicLong.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); - DEFAULT_FACTORY.put(pair(Number.class, AtomicBoolean.class), NumberConversion::toAtomicBoolean); - DEFAULT_FACTORY.put(pair(Map.class, AtomicBoolean.class), MapConversion::toAtomicBoolean); - DEFAULT_FACTORY.put(pair(String.class, AtomicBoolean.class), StringConversion::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(Void.class, AtomicBoolean.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Byte.class, AtomicBoolean.class), NumberConversions::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(Short.class, AtomicBoolean.class), NumberConversions::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(Integer.class, AtomicBoolean.class), NumberConversions::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(Long.class, AtomicBoolean.class), NumberConversions::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(Float.class, AtomicBoolean.class), NumberConversions::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(Double.class, AtomicBoolean.class), NumberConversions::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(Boolean.class, AtomicBoolean.class), BooleanConversions::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(Character.class, AtomicBoolean.class), CharacterConversions::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(BigInteger.class, AtomicBoolean.class), NumberConversions::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(BigDecimal.class, AtomicBoolean.class), NumberConversions::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, AtomicBoolean.class), AtomicBooleanConversions::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(AtomicInteger.class, AtomicBoolean.class), NumberConversions::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(AtomicLong.class, AtomicBoolean.class), NumberConversions::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(Number.class, AtomicBoolean.class), NumberConversions::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(Map.class, AtomicBoolean.class), MapConversions::toAtomicBoolean); + DEFAULT_FACTORY.put(pair(String.class, AtomicBoolean.class), StringConversions::toAtomicBoolean); // AtomicInteger conversions supported - DEFAULT_FACTORY.put(pair(Void.class, AtomicInteger.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Byte.class, AtomicInteger.class), NumberConversion::toAtomicInteger); - DEFAULT_FACTORY.put(pair(Short.class, AtomicInteger.class), NumberConversion::toAtomicInteger); - DEFAULT_FACTORY.put(pair(Integer.class, AtomicInteger.class), NumberConversion::toAtomicInteger); - DEFAULT_FACTORY.put(pair(Long.class, AtomicInteger.class), NumberConversion::toAtomicInteger); - DEFAULT_FACTORY.put(pair(Float.class, AtomicInteger.class), NumberConversion::toAtomicInteger); - DEFAULT_FACTORY.put(pair(Double.class, AtomicInteger.class), NumberConversion::toAtomicInteger); - DEFAULT_FACTORY.put(pair(Boolean.class, AtomicInteger.class), 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), AtomicBooleanConversion::toAtomicInteger); - DEFAULT_FACTORY.put(pair(AtomicLong.class, AtomicInteger.class), NumberConversion::toAtomicInteger); - 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); + DEFAULT_FACTORY.put(pair(Void.class, AtomicInteger.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Byte.class, AtomicInteger.class), NumberConversions::toAtomicInteger); + DEFAULT_FACTORY.put(pair(Short.class, AtomicInteger.class), NumberConversions::toAtomicInteger); + DEFAULT_FACTORY.put(pair(Integer.class, AtomicInteger.class), NumberConversions::toAtomicInteger); + DEFAULT_FACTORY.put(pair(Long.class, AtomicInteger.class), NumberConversions::toAtomicInteger); + DEFAULT_FACTORY.put(pair(Float.class, AtomicInteger.class), NumberConversions::toAtomicInteger); + DEFAULT_FACTORY.put(pair(Double.class, AtomicInteger.class), NumberConversions::toAtomicInteger); + DEFAULT_FACTORY.put(pair(Boolean.class, AtomicInteger.class), BooleanConversions::toAtomicInteger); + DEFAULT_FACTORY.put(pair(Character.class, AtomicInteger.class), CharacterConversions::toAtomicInteger); + DEFAULT_FACTORY.put(pair(BigInteger.class, AtomicInteger.class), NumberConversions::toAtomicInteger); + DEFAULT_FACTORY.put(pair(BigDecimal.class, AtomicInteger.class), NumberConversions::toAtomicInteger); + DEFAULT_FACTORY.put(pair(AtomicInteger.class, AtomicInteger.class), NumberConversions::toAtomicInteger); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, AtomicInteger.class), AtomicBooleanConversions::toAtomicInteger); + DEFAULT_FACTORY.put(pair(AtomicLong.class, AtomicInteger.class), NumberConversions::toAtomicInteger); + DEFAULT_FACTORY.put(pair(LocalDate.class, AtomicInteger.class), LocalDateConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(Number.class, AtomicBoolean.class), NumberConversions::toAtomicInteger); + DEFAULT_FACTORY.put(pair(Map.class, AtomicInteger.class), MapConversions::toAtomicInteger); + DEFAULT_FACTORY.put(pair(String.class, AtomicInteger.class), StringConversions::toAtomicInteger); // AtomicLong conversions supported - DEFAULT_FACTORY.put(pair(Void.class, AtomicLong.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Byte.class, AtomicLong.class), NumberConversion::toAtomicLong); - DEFAULT_FACTORY.put(pair(Short.class, AtomicLong.class), NumberConversion::toAtomicLong); - DEFAULT_FACTORY.put(pair(Integer.class, AtomicLong.class), NumberConversion::toAtomicLong); - DEFAULT_FACTORY.put(pair(Long.class, AtomicLong.class), NumberConversion::toAtomicLong); - DEFAULT_FACTORY.put(pair(Float.class, AtomicLong.class), NumberConversion::toAtomicLong); - DEFAULT_FACTORY.put(pair(Double.class, AtomicLong.class), NumberConversion::toAtomicLong); - DEFAULT_FACTORY.put(pair(Boolean.class, AtomicLong.class), BooleanConversion::toAtomicLong); - DEFAULT_FACTORY.put(pair(Character.class, AtomicLong.class), (fromInstance, converter, options) -> new AtomicLong(((char) fromInstance))); - DEFAULT_FACTORY.put(pair(BigInteger.class, AtomicLong.class), NumberConversion::toAtomicLong); - DEFAULT_FACTORY.put(pair(BigDecimal.class, AtomicLong.class), NumberConversion::toAtomicLong); - DEFAULT_FACTORY.put(pair(AtomicBoolean.class, AtomicLong.class), AtomicBooleanConversion::toAtomicLong); - DEFAULT_FACTORY.put(pair(AtomicLong.class, AtomicLong.class), Converter::identity); // mutable, so dupe - DEFAULT_FACTORY.put(pair(AtomicInteger.class, AtomicLong.class), NumberConversion::toAtomicLong); - DEFAULT_FACTORY.put(pair(Date.class, AtomicLong.class), DateConversion::toAtomicLong); - DEFAULT_FACTORY.put(pair(java.sql.Date.class, AtomicLong.class), DateConversion::toAtomicLong); - DEFAULT_FACTORY.put(pair(Timestamp.class, AtomicLong.class), DateConversion::toAtomicLong); - DEFAULT_FACTORY.put(pair(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); - DEFAULT_FACTORY.put(pair(String.class, AtomicLong.class), StringConversion::toAtomicLong); + DEFAULT_FACTORY.put(pair(Void.class, AtomicLong.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Byte.class, AtomicLong.class), NumberConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(Short.class, AtomicLong.class), NumberConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(Integer.class, AtomicLong.class), NumberConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(Long.class, AtomicLong.class), NumberConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(Float.class, AtomicLong.class), NumberConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(Double.class, AtomicLong.class), NumberConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(Boolean.class, AtomicLong.class), BooleanConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(Character.class, AtomicLong.class), CharacterConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(BigInteger.class, AtomicLong.class), NumberConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(BigDecimal.class, AtomicLong.class), NumberConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(AtomicBoolean.class, AtomicLong.class), AtomicBooleanConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(AtomicLong.class, AtomicLong.class), Converter::identity); + DEFAULT_FACTORY.put(pair(AtomicInteger.class, AtomicLong.class), NumberConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(Date.class, AtomicLong.class), DateConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, AtomicLong.class), DateConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(Timestamp.class, AtomicLong.class), DateConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(Instant.class, AtomicLong.class), InstantConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(LocalDate.class, AtomicLong.class), LocalDateConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, AtomicLong.class), LocalDateTimeConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, AtomicLong.class), ZonedDateTimeConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(Calendar.class, AtomicLong.class), CalendarConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(Number.class, AtomicLong.class), NumberConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(Map.class, AtomicLong.class), MapConversions::toAtomicLong); + DEFAULT_FACTORY.put(pair(String.class, AtomicLong.class), StringConversions::toAtomicLong); // Date conversions supported - DEFAULT_FACTORY.put(pair(Void.class, Date.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Long.class, Date.class), NumberConversion::toDate); - DEFAULT_FACTORY.put(pair(Double.class, Date.class), NumberConversion::toDate); - DEFAULT_FACTORY.put(pair(BigInteger.class, Date.class), NumberConversion::toDate); - DEFAULT_FACTORY.put(pair(BigDecimal.class, Date.class), NumberConversion::toDate); - DEFAULT_FACTORY.put(pair(AtomicLong.class, Date.class), NumberConversion::toDate); - 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(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) -> { - Map map = (Map) fromInstance; - if (map.containsKey("time")) { - return converter.convert(map.get("time"), Date.class, options); - } else { - return converter.fromValueMap(map, Date.class, CollectionUtilities.setOf("time"), options); - } - }); - DEFAULT_FACTORY.put(pair(String.class, Date.class), (fromInstance, converter, options) -> DateUtilities.parseDate(((String) fromInstance).trim())); + DEFAULT_FACTORY.put(pair(Void.class, Date.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Long.class, Date.class), NumberConversions::toDate); + DEFAULT_FACTORY.put(pair(Double.class, Date.class), NumberConversions::toDate); + DEFAULT_FACTORY.put(pair(BigInteger.class, Date.class), NumberConversions::toDate); + DEFAULT_FACTORY.put(pair(BigDecimal.class, Date.class), NumberConversions::toDate); + DEFAULT_FACTORY.put(pair(AtomicLong.class, Date.class), NumberConversions::toDate); + DEFAULT_FACTORY.put(pair(Date.class, Date.class), DateConversions::toDate); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, Date.class), DateConversions::toDate); + DEFAULT_FACTORY.put(pair(Timestamp.class, Date.class), DateConversions::toDate); + DEFAULT_FACTORY.put(pair(Instant.class, Date.class), InstantConversions::toDate); + DEFAULT_FACTORY.put(pair(LocalDate.class, Date.class), LocalDateConversions::toDate); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, Date.class), LocalDateTimeConversions::toDate); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, Date.class), ZonedDateTimeConversions::toDate); + DEFAULT_FACTORY.put(pair(Calendar.class, Date.class), CalendarConversions::toDate); + DEFAULT_FACTORY.put(pair(Number.class, Date.class), NumberConversions::toDate); + DEFAULT_FACTORY.put(pair(Map.class, Date.class), MapConversions::toDate); + DEFAULT_FACTORY.put(pair(String.class, Date.class), StringConversions::toDate); // java.sql.Date conversion supported - DEFAULT_FACTORY.put(pair(Void.class, java.sql.Date.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Long.class, java.sql.Date.class), NumberConversion::toSqlDate); - DEFAULT_FACTORY.put(pair(Double.class, java.sql.Date.class), NumberConversion::toSqlDate); - 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); - 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), 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), MapConversion::toSqlDate); - DEFAULT_FACTORY.put(pair(String.class, java.sql.Date.class), StringConversion::toSqlDate); + DEFAULT_FACTORY.put(pair(Void.class, java.sql.Date.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Long.class, java.sql.Date.class), NumberConversions::toSqlDate); + DEFAULT_FACTORY.put(pair(Double.class, java.sql.Date.class), NumberConversions::toSqlDate); + DEFAULT_FACTORY.put(pair(BigInteger.class, java.sql.Date.class), NumberConversions::toSqlDate); + DEFAULT_FACTORY.put(pair(BigDecimal.class, java.sql.Date.class), NumberConversions::toSqlDate); + DEFAULT_FACTORY.put(pair(AtomicLong.class, java.sql.Date.class), NumberConversions::toSqlDate); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, java.sql.Date.class), DateConversions::toSqlDate); + DEFAULT_FACTORY.put(pair(Date.class, java.sql.Date.class), DateConversions::toSqlDate); + DEFAULT_FACTORY.put(pair(Timestamp.class, java.sql.Date.class), DateConversions::toSqlDate); + DEFAULT_FACTORY.put(pair(Instant.class, java.sql.Date.class), InstantConversions::toSqlDate); + DEFAULT_FACTORY.put(pair(LocalDate.class, java.sql.Date.class), LocalDateConversions::toSqlDate); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, java.sql.Date.class), LocalDateTimeConversions::toSqlDate); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, java.sql.Date.class), ZonedDateTimeConversions::toSqlDate); + DEFAULT_FACTORY.put(pair(Calendar.class, java.sql.Date.class), CalendarConversions::toSqlDate); + DEFAULT_FACTORY.put(pair(Number.class, java.sql.Date.class), NumberConversions::toSqlDate); + DEFAULT_FACTORY.put(pair(Map.class, java.sql.Date.class), MapConversions::toSqlDate); + DEFAULT_FACTORY.put(pair(String.class, java.sql.Date.class), StringConversions::toSqlDate); // Timestamp conversions supported - DEFAULT_FACTORY.put(pair(Void.class, Timestamp.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Long.class, Timestamp.class), NumberConversion::toTimestamp); - DEFAULT_FACTORY.put(pair(Double.class, Timestamp.class), NumberConversion::toTimestamp); - 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), 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; - if (map.containsKey("time")) { - long time = converter.convert(map.get("time"), long.class, options); - int ns = converter.convert(map.get("nanos"), int.class, options); - Timestamp timeStamp = new Timestamp(time); - timeStamp.setNanos(ns); - return timeStamp; - } else { - return converter.fromValueMap(map, Timestamp.class, CollectionUtilities.setOf("time", "nanos"), options); - } - }); + DEFAULT_FACTORY.put(pair(Void.class, Timestamp.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Long.class, Timestamp.class), NumberConversions::toTimestamp); + DEFAULT_FACTORY.put(pair(Double.class, Timestamp.class), NumberConversions::toTimestamp); + DEFAULT_FACTORY.put(pair(BigInteger.class, Timestamp.class), NumberConversions::toTimestamp); + DEFAULT_FACTORY.put(pair(BigDecimal.class, Timestamp.class), NumberConversions::toTimestamp); + DEFAULT_FACTORY.put(pair(AtomicLong.class, Timestamp.class), NumberConversions::toTimestamp); + DEFAULT_FACTORY.put(pair(Timestamp.class, Timestamp.class), DateConversions::toTimestamp); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, Timestamp.class), DateConversions::toTimestamp); + DEFAULT_FACTORY.put(pair(Date.class, Timestamp.class), DateConversions::toTimestamp); + DEFAULT_FACTORY.put(pair(Instant.class,Timestamp.class), InstantConversions::toTimestamp); + DEFAULT_FACTORY.put(pair(LocalDate.class, Timestamp.class), LocalDateConversions::toTimestamp); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, Timestamp.class), LocalDateTimeConversions::toTimestamp); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, Timestamp.class), ZonedDateTimeConversions::toTimestamp); + DEFAULT_FACTORY.put(pair(Calendar.class, Timestamp.class), CalendarConversions::toTimestamp); + DEFAULT_FACTORY.put(pair(Number.class, Timestamp.class), NumberConversions::toTimestamp); + DEFAULT_FACTORY.put(pair(Map.class, Timestamp.class), MapConversions::toTimestamp); DEFAULT_FACTORY.put(pair(String.class, Timestamp.class), (fromInstance, converter, options) -> { String str = ((String) fromInstance).trim(); Date date = DateUtilities.parseDate(str); @@ -505,20 +474,21 @@ private static void buildFactoryConversions() { }); // Calendar conversions supported - DEFAULT_FACTORY.put(pair(Void.class, Calendar.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Long.class, Calendar.class), NumberConversion::toCalendar); - DEFAULT_FACTORY.put(pair(Double.class, Calendar.class), NumberConversion::toCalendar); - 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), 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(Void.class, Calendar.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Long.class, Calendar.class), NumberConversions::toCalendar); + DEFAULT_FACTORY.put(pair(Double.class, Calendar.class), NumberConversions::toCalendar); + DEFAULT_FACTORY.put(pair(BigInteger.class, Calendar.class), NumberConversions::toCalendar); + DEFAULT_FACTORY.put(pair(BigDecimal.class, Calendar.class), NumberConversions::toCalendar); + DEFAULT_FACTORY.put(pair(AtomicLong.class, Calendar.class), NumberConversions::toCalendar); + DEFAULT_FACTORY.put(pair(Date.class, Calendar.class), DateConversions::toCalendar); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, Calendar.class), DateConversions::toCalendar); + DEFAULT_FACTORY.put(pair(Timestamp.class, Calendar.class), DateConversions::toCalendar); + DEFAULT_FACTORY.put(pair(Instant.class, Calendar.class), InstantConversions::toCalendar); + DEFAULT_FACTORY.put(pair(LocalDate.class, Calendar.class), LocalDateConversions::toCalendar); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, Calendar.class), LocalDateTimeConversions::toCalendar); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, Calendar.class), ZonedDateTimeConversions::toCalendar); + DEFAULT_FACTORY.put(pair(Calendar.class, Calendar.class), CalendarConversions::clone); + DEFAULT_FACTORY.put(pair(Number.class, Calendar.class), NumberConversions::toCalendar); DEFAULT_FACTORY.put(pair(Map.class, Calendar.class), (fromInstance, converter, options) -> { Map map = (Map) fromInstance; if (map.containsKey("time")) { @@ -545,11 +515,12 @@ private static void buildFactoryConversions() { if (date == null) { return null; } - return CalendarConversion.create(date.getTime(), options); + return CalendarConversions.create(date.getTime(), options); }); + // LocalTime conversions supported - DEFAULT_FACTORY.put(pair(Void.class, LocalTime.class), VoidConversion::toNull); + DEFAULT_FACTORY.put(pair(Void.class, LocalTime.class), VoidConversions::toNull); DEFAULT_FACTORY.put(pair(LocalTime.class, LocalTime.class), Converter::identity); DEFAULT_FACTORY.put(pair(String.class, LocalTime.class), (fromInstance, converter, options) -> { String strTime = (String) fromInstance; @@ -573,21 +544,21 @@ private static void buildFactoryConversions() { }); // LocalDate conversions supported - DEFAULT_FACTORY.put(pair(Void.class, LocalDate.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Long.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(AtomicLong.class, LocalDate.class), NumberConversion::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), 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(Void.class, LocalDate.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Long.class, LocalDate.class), NumberConversions::toLocalDate); + DEFAULT_FACTORY.put(pair(Double.class, LocalDate.class), NumberConversions::toLocalDate); + DEFAULT_FACTORY.put(pair(BigInteger.class, LocalDate.class), NumberConversions::toLocalDate); + DEFAULT_FACTORY.put(pair(BigDecimal.class, LocalDate.class), NumberConversions::toLocalDate); + DEFAULT_FACTORY.put(pair(AtomicLong.class, LocalDate.class), NumberConversions::toLocalDate); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, LocalDate.class), DateConversions::toLocalDate); + DEFAULT_FACTORY.put(pair(Timestamp.class, LocalDate.class), DateConversions::toLocalDate); + DEFAULT_FACTORY.put(pair(Date.class, LocalDate.class), DateConversions::toLocalDate); + DEFAULT_FACTORY.put(pair(Instant.class, LocalDate.class), InstantConversions::toLocalDate); + DEFAULT_FACTORY.put(pair(LocalDate.class, LocalDate.class), LocalDateConversions::toLocalDate); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, LocalDate.class), LocalDateTimeConversions::toLocalDate); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, LocalDate.class), ZonedDateTimeConversions::toLocalDate); + DEFAULT_FACTORY.put(pair(Calendar.class, LocalDate.class), CalendarConversions::toLocalDate); + DEFAULT_FACTORY.put(pair(Number.class, LocalDate.class), NumberConversions::toLocalDate); DEFAULT_FACTORY.put(pair(Map.class, LocalDate.class), (fromInstance, converter, options) -> { Map map = (Map) fromInstance; if (map.containsKey("month") && map.containsKey("day") && map.containsKey("year")) { @@ -609,21 +580,21 @@ private static void buildFactoryConversions() { }); // LocalDateTime conversions supported - DEFAULT_FACTORY.put(pair(Void.class, LocalDateTime.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Long.class, LocalDateTime.class), NumberConversion::toLocalDateTime); - DEFAULT_FACTORY.put(pair(Double.class, LocalDateTime.class), NumberConversion::toLocalDateTime); - 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), 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), 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(Void.class, LocalDateTime.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Long.class, LocalDateTime.class), NumberConversions::toLocalDateTime); + DEFAULT_FACTORY.put(pair(Double.class, LocalDateTime.class), NumberConversions::toLocalDateTime); + DEFAULT_FACTORY.put(pair(BigInteger.class, LocalDateTime.class), NumberConversions::toLocalDateTime); + DEFAULT_FACTORY.put(pair(BigDecimal.class, LocalDateTime.class), NumberConversions::toLocalDateTime); + DEFAULT_FACTORY.put(pair(AtomicLong.class, LocalDateTime.class), NumberConversions::toLocalDateTime); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, LocalDateTime.class), DateConversions::toLocalDateTime); + DEFAULT_FACTORY.put(pair(Timestamp.class, LocalDateTime.class), DateConversions::toLocalDateTime); + DEFAULT_FACTORY.put(pair(Date.class, LocalDateTime.class), DateConversions::toLocalDateTime); + DEFAULT_FACTORY.put(pair(Instant.class, LocalDateTime.class), InstantConversions::toLocalDateTime); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, LocalDateTime.class), LocalDateTimeConversions::toLocalDateTime); + DEFAULT_FACTORY.put(pair(LocalDate.class, LocalDateTime.class), LocalDateConversions::toLocalDateTime); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, LocalDateTime.class), ZonedDateTimeConversions::toLocalDateTime); + DEFAULT_FACTORY.put(pair(Calendar.class, LocalDateTime.class), CalendarConversions::toLocalDateTime); + DEFAULT_FACTORY.put(pair(Number.class, LocalDateTime.class), NumberConversions::toLocalDateTime); DEFAULT_FACTORY.put(pair(Map.class, LocalDateTime.class), (fromInstance, converter, options) -> { Map map = (Map) fromInstance; return converter.fromValueMap(map, LocalDateTime.class, null, options); @@ -637,21 +608,52 @@ private static void buildFactoryConversions() { return date.toInstant().atZone(options.getZoneId()).toLocalDateTime(); }); + DEFAULT_FACTORY.put(pair(Void.class, LocalTime.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Long.class, LocalTime.class), NumberConversions::toLocalTime); + DEFAULT_FACTORY.put(pair(Double.class, LocalTime.class), NumberConversions::toLocalTime); + DEFAULT_FACTORY.put(pair(BigInteger.class, LocalTime.class), NumberConversions::toLocalTime); + DEFAULT_FACTORY.put(pair(BigDecimal.class, LocalTime.class), NumberConversions::toLocalDateTime); + DEFAULT_FACTORY.put(pair(AtomicLong.class, LocalTime.class), NumberConversions::toLocalTime); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, LocalTime.class), DateConversions::toLocalTime); + DEFAULT_FACTORY.put(pair(Timestamp.class, LocalTime.class), DateConversions::toLocalTime); + DEFAULT_FACTORY.put(pair(Date.class, LocalTime.class), DateConversions::toLocalTime); + DEFAULT_FACTORY.put(pair(Instant.class, LocalTime.class), InstantConversions::toLocalTime); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, LocalTime.class), LocalDateTimeConversions::toLocalTime); + DEFAULT_FACTORY.put(pair(LocalDate.class, LocalTime.class), LocalDateConversions::toLocalTime); + DEFAULT_FACTORY.put(pair(LocalTime.class, LocalTime.class), Converter::identity); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, LocalTime.class), ZonedDateTimeConversions::toLocalTime); + DEFAULT_FACTORY.put(pair(Calendar.class, LocalTime.class), CalendarConversions::toLocalTime); + DEFAULT_FACTORY.put(pair(Number.class, LocalTime.class), NumberConversions::toLocalTime); + DEFAULT_FACTORY.put(pair(Map.class, LocalTime.class), (fromInstance, converter, options) -> { + Map map = (Map) fromInstance; + return converter.fromValueMap(map, LocalTime.class, null, options); + }); + DEFAULT_FACTORY.put(pair(String.class, LocalTime.class), (fromInstance, converter, options) -> { + String str = StringUtilities.trimToEmpty((String)fromInstance); + Date date = DateUtilities.parseDate(str); + if (date == null) { + return null; + } + return converter.convert(date, LocalTime.class, options); + }); + + // ZonedDateTime conversions supported - DEFAULT_FACTORY.put(pair(Void.class, ZonedDateTime.class), VoidConversion::toNull); - DEFAULT_FACTORY.put(pair(Long.class, ZonedDateTime.class), NumberConversion::toZonedDateTime); - DEFAULT_FACTORY.put(pair(Double.class, ZonedDateTime.class), NumberConversion::toZonedDateTime); - 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), 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(Void.class, ZonedDateTime.class), VoidConversions::toNull); + DEFAULT_FACTORY.put(pair(Long.class, ZonedDateTime.class), NumberConversions::toZonedDateTime); + DEFAULT_FACTORY.put(pair(Double.class, ZonedDateTime.class), NumberConversions::toZonedDateTime); + DEFAULT_FACTORY.put(pair(BigInteger.class, ZonedDateTime.class), NumberConversions::toZonedDateTime); + DEFAULT_FACTORY.put(pair(BigDecimal.class, ZonedDateTime.class), NumberConversions::toZonedDateTime); + DEFAULT_FACTORY.put(pair(AtomicLong.class, ZonedDateTime.class), NumberConversions::toZonedDateTime); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, ZonedDateTime.class), DateConversions::toZonedDateTime); + DEFAULT_FACTORY.put(pair(Timestamp.class, ZonedDateTime.class), DateConversions::toZonedDateTime); + DEFAULT_FACTORY.put(pair(Date.class, ZonedDateTime.class), DateConversions::toZonedDateTime); + DEFAULT_FACTORY.put(pair(Instant.class, ZonedDateTime.class), InstantConversions::toZonedDateTime); + DEFAULT_FACTORY.put(pair(LocalDate.class, ZonedDateTime.class), LocalDateConversions::toZonedDateTime); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, ZonedDateTime.class), LocalDateTimeConversions::toZonedDateTime); DEFAULT_FACTORY.put(pair(ZonedDateTime.class, ZonedDateTime.class), Converter::identity); - DEFAULT_FACTORY.put(pair(Calendar.class, ZonedDateTime.class), CalendarConversion::toZonedDateTime); - DEFAULT_FACTORY.put(pair(Number.class, ZonedDateTime.class), NumberConversion::toZonedDateTime); + DEFAULT_FACTORY.put(pair(Calendar.class, ZonedDateTime.class), CalendarConversions::toZonedDateTime); + DEFAULT_FACTORY.put(pair(Number.class, ZonedDateTime.class), NumberConversions::toZonedDateTime); DEFAULT_FACTORY.put(pair(Map.class, ZonedDateTime.class), (fromInstance, converter, options) -> { Map map = (Map) fromInstance; return converter.fromValueMap(map, ZonedDateTime.class, null, options); @@ -662,11 +664,11 @@ private static void buildFactoryConversions() { if (date == null) { return null; } - return date.toInstant().atZone(options.getZoneId()); + return converter.convert(date, ZonedDateTime.class, options); }); // UUID conversions supported - DEFAULT_FACTORY.put(pair(Void.class, UUID.class), VoidConversion::toNull); + DEFAULT_FACTORY.put(pair(Void.class, UUID.class), VoidConversions::toNull); DEFAULT_FACTORY.put(pair(UUID.class, UUID.class), Converter::identity); DEFAULT_FACTORY.put(pair(String.class, UUID.class), (fromInstance, converter, options) -> UUID.fromString(((String) fromInstance).trim())); DEFAULT_FACTORY.put(pair(BigInteger.class, UUID.class), (fromInstance, converter, options) -> { @@ -682,10 +684,10 @@ private static void buildFactoryConversions() { long leastSigBits = bigInt.and(new BigInteger("FFFFFFFFFFFFFFFF", 16)).longValue(); return new UUID(mostSigBits, leastSigBits); }); - DEFAULT_FACTORY.put(pair(Map.class, UUID.class), MapConversion::toUUID); + DEFAULT_FACTORY.put(pair(Map.class, UUID.class), MapConversions::toUUID); // Class conversions supported - DEFAULT_FACTORY.put(pair(Void.class, Class.class), VoidConversion::toNull); + DEFAULT_FACTORY.put(pair(Void.class, Class.class), VoidConversions::toNull); DEFAULT_FACTORY.put(pair(Class.class, Class.class), Converter::identity); DEFAULT_FACTORY.put(pair(Map.class, Class.class), (fromInstance, converter, options) -> converter.fromValueMap((Map) fromInstance, AtomicLong.class, null, options)); DEFAULT_FACTORY.put(pair(String.class, Class.class), (fromInstance, converter, options) -> { @@ -698,7 +700,7 @@ private static void buildFactoryConversions() { }); // String conversions supported - DEFAULT_FACTORY.put(pair(Void.class, String.class), VoidConversion::toNull); + DEFAULT_FACTORY.put(pair(Void.class, String.class), VoidConversions::toNull); DEFAULT_FACTORY.put(pair(Byte.class, String.class), Converter::toString); DEFAULT_FACTORY.put(pair(Short.class, String.class), Converter::toString); DEFAULT_FACTORY.put(pair(Integer.class, String.class), Converter::toString); @@ -744,7 +746,7 @@ private static void buildFactoryConversions() { return simpleDateFormat.format(((Calendar) fromInstance).getTime()); }); DEFAULT_FACTORY.put(pair(Number.class, String.class), Converter::toString); - DEFAULT_FACTORY.put(pair(Map.class, String.class), MapConversion::toString); + DEFAULT_FACTORY.put(pair(Map.class, String.class), MapConversions::toString); DEFAULT_FACTORY.put(pair(Enum.class, String.class), (fromInstance, converter, options) -> ((Enum) fromInstance).name()); DEFAULT_FACTORY.put(pair(String.class, String.class), Converter::identity); DEFAULT_FACTORY.put(pair(Duration.class, String.class), Converter::toString); @@ -753,7 +755,7 @@ private static void buildFactoryConversions() { DEFAULT_FACTORY.put(pair(MonthDay.class, String.class), Converter::toString); // Duration conversions supported - DEFAULT_FACTORY.put(pair(Void.class, Duration.class), VoidConversion::toNull); + DEFAULT_FACTORY.put(pair(Void.class, Duration.class), VoidConversions::toNull); DEFAULT_FACTORY.put(pair(Duration.class, Duration.class), Converter::identity); DEFAULT_FACTORY.put(pair(String.class, Duration.class), (fromInstance, converter, options) -> Duration.parse((String) fromInstance)); DEFAULT_FACTORY.put(pair(Map.class, Duration.class), (fromInstance, converter, options) -> { @@ -768,34 +770,23 @@ private static void buildFactoryConversions() { }); // Instant conversions supported - DEFAULT_FACTORY.put(pair(Void.class, Instant.class), VoidConversion::toNull); + DEFAULT_FACTORY.put(pair(Void.class, Instant.class), VoidConversions::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); - } catch (Exception e) { - return DateUtilities.parseDate((String) fromInstance).toInstant(); - } - }); + DEFAULT_FACTORY.put(pair(Long.class, Instant.class), NumberConversions::toInstant); + DEFAULT_FACTORY.put(pair(Double.class, Instant.class), NumberConversions::toInstant); + DEFAULT_FACTORY.put(pair(BigInteger.class, Instant.class), NumberConversions::toInstant); + DEFAULT_FACTORY.put(pair(BigDecimal.class, Instant.class), NumberConversions::toInstant); + DEFAULT_FACTORY.put(pair(AtomicLong.class, Instant.class), NumberConversions::toInstant); + DEFAULT_FACTORY.put(pair(java.sql.Date.class, Instant.class), DateConversions::toInstant); + DEFAULT_FACTORY.put(pair(Timestamp.class, Instant.class), DateConversions::toInstant); + DEFAULT_FACTORY.put(pair(Date.class, Instant.class), DateConversions::toInstant); + DEFAULT_FACTORY.put(pair(LocalDate.class, Instant.class), LocalDateConversions::toInstant); + DEFAULT_FACTORY.put(pair(LocalDateTime.class, Instant.class), LocalDateTimeConversions::toInstant); + DEFAULT_FACTORY.put(pair(ZonedDateTime.class, Instant.class), ZonedDateTimeConversions::toInstant); + DEFAULT_FACTORY.put(pair(Calendar.class, Instant.class), CalendarConversions::toInstant); + DEFAULT_FACTORY.put(pair(Number.class, Instant.class), NumberConversions::toInstant); + + DEFAULT_FACTORY.put(pair(String.class, Instant.class), StringConversions::toInstant); DEFAULT_FACTORY.put(pair(Map.class, Instant.class), (fromInstance, converter, options) -> { Map map = (Map) fromInstance; if (map.containsKey("seconds")) { @@ -817,7 +808,7 @@ private static void buildFactoryConversions() { // java.time.ZoneRegion = com.cedarsoftware.util.io.DEFAULT_FACTORY.ZoneIdFactory // MonthDay conversions supported - DEFAULT_FACTORY.put(pair(Void.class, MonthDay.class), VoidConversion::toNull); + DEFAULT_FACTORY.put(pair(Void.class, MonthDay.class), VoidConversions::toNull); DEFAULT_FACTORY.put(pair(MonthDay.class, MonthDay.class), Converter::identity); DEFAULT_FACTORY.put(pair(String.class, MonthDay.class), (fromInstance, converter, options) -> { String monthDay = (String) fromInstance; @@ -835,7 +826,7 @@ private static void buildFactoryConversions() { }); // Map conversions supported - DEFAULT_FACTORY.put(pair(Void.class, Map.class), VoidConversion::toNull); + DEFAULT_FACTORY.put(pair(Void.class, Map.class), VoidConversions::toNull); DEFAULT_FACTORY.put(pair(Byte.class, Map.class), Converter::initMap); DEFAULT_FACTORY.put(pair(Short.class, Map.class), Converter::initMap); DEFAULT_FACTORY.put(pair(Integer.class, Map.class), Converter::initMap); diff --git a/src/main/java/com/cedarsoftware/util/convert/ConverterOptions.java b/src/main/java/com/cedarsoftware/util/convert/ConverterOptions.java index 30008478..60f74f84 100644 --- a/src/main/java/com/cedarsoftware/util/convert/ConverterOptions.java +++ b/src/main/java/com/cedarsoftware/util/convert/ConverterOptions.java @@ -65,4 +65,16 @@ public interface ConverterOptions { * @return TimeZone expected on the target when finished (only for types that support ZoneId or TimeZone) */ default TimeZone getTimeZone() { return TimeZone.getTimeZone(this.getZoneId()); } + + /** + * Character to return for boolean to Character conversion when the boolean is true. + * @return the Character representing true + */ + default Character trueChar() { return CommonValues.CHARACTER_ONE; } + + /** + * Character to return for boolean to Character conversion when the boolean is false. + * @return the Character representing false + */ + default Character falseChar() { return CommonValues.CHARACTER_ZERO; } } diff --git a/src/main/java/com/cedarsoftware/util/convert/DateConversion.java b/src/main/java/com/cedarsoftware/util/convert/DateConversions.java similarity index 58% rename from src/main/java/com/cedarsoftware/util/convert/DateConversion.java rename to src/main/java/com/cedarsoftware/util/convert/DateConversions.java index fb2ca26a..0c733564 100644 --- a/src/main/java/com/cedarsoftware/util/convert/DateConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/DateConversions.java @@ -6,12 +6,13 @@ 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 DateConversion { +public class DateConversions { static long toLong(Object fromInstance) { return ((Date) fromInstance).getTime(); @@ -29,16 +30,43 @@ static long toLong(Object fromInstance, Converter converter, ConverterOptions op return toLong(fromInstance); } - static Date toSqlDate(Object fromInstance, Converter converter, ConverterOptions options) { + /** + * The input can be any of our Date type objects (java.sql.Date, Timestamp, Date, etc.) coming in so + * we need to force the conversion by creating a new instance. + * @param fromInstance - one of the date objects + * @param converter - converter instance + * @param options - converter options + * @return newly created java.sql.Date + */ + static java.sql.Date toSqlDate(Object fromInstance, Converter converter, ConverterOptions options) { return new java.sql.Date(toLong(fromInstance)); } + /** + * The input can be any of our Date type objects (java.sql.Date, Timestamp, Date, etc.) coming in so + * we need to force the conversion by creating a new instance. + * @param fromInstance - one of the date objects + * @param converter - converter instance + * @param options - converter options + * @return newly created Date + */ static Date toDate(Object fromInstance, Converter converter, ConverterOptions options) { + return new Date(toLong(fromInstance)); + } + + /** + * The input can be any of our Date type objects (java.sql.Date, Timestamp, Date, etc.) coming in so + * we need to force the conversion by creating a new instance. + * @param fromInstance - one of the date objects + * @param converter - converter instance + * @param options - converter options + * @return newly created Timestamp + */ 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); + return CalendarConversions.create(toLong(fromInstance), options); } static BigDecimal toBigDecimal(Object fromInstance, Converter converter, ConverterOptions options) { @@ -61,6 +89,10 @@ static LocalDate toLocalDate(Object fromInstance, Converter converter, Converter return toZonedDateTime(fromInstance, options).toLocalDate(); } + static LocalTime toLocalTime(Object fromInstance, Converter converter, ConverterOptions options) { + return toZonedDateTime(fromInstance, options).toLocalTime(); + } + static BigInteger toBigInteger(Object fromInstance, Converter converter, ConverterOptions options) { return BigInteger.valueOf(toLong(fromInstance)); } diff --git a/src/main/java/com/cedarsoftware/util/convert/InstantConversion.java b/src/main/java/com/cedarsoftware/util/convert/InstantConversion.java deleted file mode 100644 index e8704d9b..00000000 --- a/src/main/java/com/cedarsoftware/util/convert/InstantConversion.java +++ /dev/null @@ -1,67 +0,0 @@ -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/InstantConversions.java b/src/main/java/com/cedarsoftware/util/convert/InstantConversions.java new file mode 100644 index 00000000..06ef1184 --- /dev/null +++ b/src/main/java/com/cedarsoftware/util/convert/InstantConversions.java @@ -0,0 +1,80 @@ +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 InstantConversions { + + static long toLong(Object from) { + return ((Instant)from).toEpochMilli(); + } + + static ZonedDateTime toZonedDateTime(Object from, ConverterOptions options) { + return ((Instant)from).atZone(options.getZoneId()); + } + + static long toLong(Object from, Converter converter, ConverterOptions options) { + return toLong(from); + } + + static float toFloat(Object from, Converter converter, ConverterOptions options) { + return toLong(from); + } + + static double toDouble(Object from, Converter converter, ConverterOptions options) { + return toLong(from); + } + + static AtomicLong toAtomicLong(Object from, Converter converter, ConverterOptions options) { + return new AtomicLong(toLong(from)); + } + + static Timestamp toTimestamp(Object from, Converter converter, ConverterOptions options) { + return new Timestamp(toLong(from)); + } + + static java.sql.Date toSqlDate(Object from, Converter converter, ConverterOptions options) { + return new java.sql.Date(toLong(from)); + } + + static Date toDate(Object from, Converter converter, ConverterOptions options) { + return new Date(toLong(from)); + } + + static Calendar toCalendar(Object from, Converter converter, ConverterOptions options) { + return CalendarConversions.create(toLong(from), options); + } + + static BigInteger toBigInteger(Object from, Converter converter, ConverterOptions options) { + return BigInteger.valueOf(toLong(from)); + } + + static BigDecimal toBigDecimal(Object from, Converter converter, ConverterOptions options) { + return BigDecimal.valueOf(toLong(from)); + } + + static ZonedDateTime toZonedDateTime(Object from, Converter converter, ConverterOptions options) { + return toZonedDateTime(from, options); + } + + static LocalDateTime toLocalDateTime(Object from, Converter converter, ConverterOptions options) { + return toZonedDateTime(from, options).toLocalDateTime(); + } + + static LocalDate toLocalDate(Object from, Converter converter, ConverterOptions options) { + return toZonedDateTime(from, options).toLocalDate(); + } + + static LocalTime toLocalTime(Object from, Converter converter, ConverterOptions options) { + return toZonedDateTime(from, options).toLocalTime(); + } +} diff --git a/src/main/java/com/cedarsoftware/util/convert/LocalDateConversion.java b/src/main/java/com/cedarsoftware/util/convert/LocalDateConversions.java similarity index 74% rename from src/main/java/com/cedarsoftware/util/convert/LocalDateConversion.java rename to src/main/java/com/cedarsoftware/util/convert/LocalDateConversions.java index 0a5ef087..50e19dce 100644 --- a/src/main/java/com/cedarsoftware/util/convert/LocalDateConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/LocalDateConversions.java @@ -6,15 +6,17 @@ 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.GregorianCalendar; import java.util.concurrent.atomic.AtomicLong; -public class LocalDateConversion { +public class LocalDateConversions { private static ZonedDateTime toZonedDateTime(Object fromInstance, ConverterOptions options) { - return ((LocalDate)fromInstance).atStartOfDay(options.getZoneId()); + return ((LocalDate)fromInstance).atStartOfDay(options.getSourceZoneIdForLocalDates()).withZoneSameInstant(options.getZoneId()); } static Instant toInstant(Object fromInstance, ConverterOptions options) { @@ -29,6 +31,14 @@ static LocalDateTime toLocalDateTime(Object fromInstance, Converter converter, C return toZonedDateTime(fromInstance, options).toLocalDateTime(); } + static LocalDate toLocalDate(Object fromInstance, Converter converter, ConverterOptions options) { + return toZonedDateTime(fromInstance, options).toLocalDate(); + } + + static LocalTime toLocalTime(Object fromInstance, Converter converter, ConverterOptions options) { + return toZonedDateTime(fromInstance, options).toLocalTime(); + } + static ZonedDateTime toZonedDateTime(Object fromInstance, Converter converter, ConverterOptions options) { return toZonedDateTime(fromInstance, options).withZoneSameInstant(options.getZoneId()); } @@ -42,6 +52,13 @@ static long toLong(Object fromInstance, Converter converter, ConverterOptions op return toInstant(fromInstance, options).toEpochMilli(); } + /** + * Warning: Can lose precision going from a full long down to a floating point number + * @param fromInstance instance to convert + * @param converter converter instance + * @param options converter options + * @return the floating point number cast from a lont. + */ static float toFloat(Object fromInstance, Converter converter, ConverterOptions options) { return toLong(fromInstance, converter, options); } @@ -60,7 +77,10 @@ static Timestamp toTimestamp(Object fromInstance, Converter converter, Converter } static Calendar toCalendar(Object fromInstance, Converter converter, ConverterOptions options) { - return CalendarConversion.create(toLong(fromInstance, options), 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) { diff --git a/src/main/java/com/cedarsoftware/util/convert/LocalDateTimeConversion.java b/src/main/java/com/cedarsoftware/util/convert/LocalDateTimeConversions.java similarity index 78% rename from src/main/java/com/cedarsoftware/util/convert/LocalDateTimeConversion.java rename to src/main/java/com/cedarsoftware/util/convert/LocalDateTimeConversions.java index 0a433b21..d98a2e0c 100644 --- a/src/main/java/com/cedarsoftware/util/convert/LocalDateTimeConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/LocalDateTimeConversions.java @@ -6,15 +6,16 @@ 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.GregorianCalendar; import java.util.concurrent.atomic.AtomicLong; -public class LocalDateTimeConversion { +public class LocalDateTimeConversions { private static ZonedDateTime toZonedDateTime(Object fromInstance, ConverterOptions options) { - return ((LocalDateTime)fromInstance).atZone(options.getSourceZoneIdForLocalDates()); + return ((LocalDateTime)fromInstance).atZone(options.getSourceZoneIdForLocalDates()).withZoneSameInstant(options.getZoneId()); } private static Instant toInstant(Object fromInstance, ConverterOptions options) { @@ -26,7 +27,19 @@ private static long toLong(Object fromInstance, ConverterOptions options) { } static ZonedDateTime toZonedDateTime(Object fromInstance, Converter converter, ConverterOptions options) { - return toZonedDateTime(fromInstance, options).withZoneSameInstant(options.getZoneId()); + 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 LocalTime toLocalTime(Object fromInstance, Converter converter, ConverterOptions options) { + return toZonedDateTime(fromInstance, options).toLocalTime(); } static Instant toInstant(Object fromInstance, Converter converter, ConverterOptions options) { diff --git a/src/main/java/com/cedarsoftware/util/convert/MapConversion.java b/src/main/java/com/cedarsoftware/util/convert/MapConversions.java similarity index 57% rename from src/main/java/com/cedarsoftware/util/convert/MapConversion.java rename to src/main/java/com/cedarsoftware/util/convert/MapConversions.java index 1c688c95..51c90876 100644 --- a/src/main/java/com/cedarsoftware/util/convert/MapConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/MapConversions.java @@ -1,34 +1,42 @@ package com.cedarsoftware.util.convert; +import com.cedarsoftware.util.ArrayUtilities; import com.cedarsoftware.util.Convention; import java.math.BigDecimal; import java.math.BigInteger; -import java.util.Arrays; +import java.sql.Timestamp; +import java.util.Date; 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 { +public class MapConversions { private static final String V = "_v"; private static final String VALUE = "value"; + private static final String TIME = "time"; + private static final String NANOS = "nanos"; + + private static final String MOST_SIG_BITS = "mostSigBits"; + private static final String LEAST_SIG_BITS = "leastSigBits"; + + + public static final String KEY_VALUE_ERROR_MESSAGE = "To convert from Map to %s the map must include one of the following: %s[_v], or [value] with associated values."; + private static String[] UUID_PARAMS = new String[] { MOST_SIG_BITS, LEAST_SIG_BITS }; static Object toUUID(Object fromInstance, Converter converter, ConverterOptions options) { Map map = (Map) fromInstance; - if (map.containsKey("mostSigBits") && map.containsKey("leastSigBits")) { - long most = converter.convert(map.get("mostSigBits"), long.class, options); - long least = converter.convert(map.get("leastSigBits"), long.class, options); - + if (map.containsKey(MOST_SIG_BITS) && map.containsKey(LEAST_SIG_BITS)) { + long most = converter.convert(map.get(MOST_SIG_BITS), long.class, options); + long least = converter.convert(map.get(LEAST_SIG_BITS), long.class, options); return new UUID(most, least); } - throw new IllegalArgumentException("To convert Map to UUID, the Map must contain both 'mostSigBits' and 'leastSigBits' keys"); + return fromValueForMultiKey(fromInstance, converter, options, UUID.class, UUID_PARAMS); } static Byte toByte(Object fromInstance, Converter converter, ConverterOptions options) { @@ -83,50 +91,61 @@ static AtomicBoolean toAtomicBoolean(Object fromInstance, Converter converter, C 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); + return fromSingleKey(fromInstance, converter, options, TIME, java.sql.Date.class); + } + + static Date toDate(Object fromInstance, Converter converter, ConverterOptions options) { + return fromSingleKey(fromInstance, converter, options, TIME, Date.class); + } + + private static final String[] TIMESTAMP_PARAMS = new String[] { TIME, NANOS }; + static Timestamp toTimestamp(Object fromInstance, Converter converter, ConverterOptions options) { + Map map = (Map) fromInstance; + if (map.containsKey("time")) { + long time = converter.convert(map.get("time"), long.class, options); + int ns = converter.convert(map.get("nanos"), int.class, options); + Timestamp timeStamp = new Timestamp(time); + timeStamp.setNanos(ns); + return timeStamp; + } + + return fromValueForMultiKey(map, converter, options, Timestamp.class, TIMESTAMP_PARAMS); } + /** * 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. + * @return type if it exists, else returns what is in V or 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"); + static T fromSingleKey(final Object fromInstance, final Converter converter, final ConverterOptions options, final String key, final Class type) { + validateParams(converter, options, type); - Map map = (Map) fromInstance; + Map map = asMap(fromInstance); if (map.containsKey(key)) { return converter.convert(key, type, options); } - if (map.containsKey(V)) { - return converter.convert(map.get(V), type, options); - } + return extractValue(map, converter, options, type, key); + } - if (map.containsKey(VALUE)) { - return converter.convert(map.get(VALUE), type, options); - } + static T fromValueForMultiKey(Object from, Converter converter, ConverterOptions options, Class type, String[] keys) { + validateParams(converter, options, type); - 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)); + return extractValue(asMap(from), converter, options, type, keys); } - 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"); + static T fromValue(Object from, Converter converter, ConverterOptions options, Class type) { + validateParams(converter, options, type); - Map map = (Map) fromInstance; + return extractValue(asMap(from), converter, options, type); + } + private static T extractValue(Map map, Converter converter, ConverterOptions options, Class type, String...keys) { if (map.containsKey(V)) { return converter.convert(map.get(V), type, options); } @@ -135,19 +154,22 @@ static T fromValue(Object fromInstance, Converter converter, ConverterOption return converter.convert(map.get(VALUE), type, options); } - 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(); + String keyText = ArrayUtilities.isEmpty(keys) ? "" : "[" + String.join(",", keys) + "], "; + throw new IllegalArgumentException(String.format(KEY_VALUE_ERROR_MESSAGE, getShortName(type), keyText)); } - private static T getConvertedValue(Map map, String key, Class type, Converter converter, ConverterOptions options) { - // NOPE STUFF? - return converter.convert(map.get(key), type, options); + private static void validateParams(Converter converter, ConverterOptions options, Class type) { + Convention.throwIfNull(type, "type cannot be null"); + Convention.throwIfNull(converter, "converter cannot be null"); + Convention.throwIfNull(options, "options cannot be null"); } private static String getShortName(Class type) { return java.sql.Date.class.equals(type) ? type.getName() : type.getSimpleName(); } + + private static Map asMap(Object o) { + Convention.throwIfFalse(o instanceof Map, "fromInstance must be an instance of map"); + return (Map)o; + } } diff --git a/src/main/java/com/cedarsoftware/util/convert/NumberConversion.java b/src/main/java/com/cedarsoftware/util/convert/NumberConversions.java similarity index 85% rename from src/main/java/com/cedarsoftware/util/convert/NumberConversion.java rename to src/main/java/com/cedarsoftware/util/convert/NumberConversions.java index 1c968e79..2e163243 100644 --- a/src/main/java/com/cedarsoftware/util/convert/NumberConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/NumberConversions.java @@ -6,6 +6,7 @@ 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; @@ -30,7 +31,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -public class NumberConversion { +public class NumberConversions { static byte toByte(Object from, Converter converter, ConverterOptions options) { return ((Number)from).byteValue(); @@ -100,7 +101,6 @@ static Double toDoubleZero(Object from, Converter converter, ConverterOptions op static BigDecimal integerTypeToBigDecimal(Object from, Converter converter, ConverterOptions options) { return BigDecimal.valueOf(toLong(from)); } - static BigInteger integerTypeToBigInteger(Object from, Converter converter, ConverterOptions options) { return BigInteger.valueOf(toLong(from)); } @@ -121,6 +121,10 @@ static BigInteger bigDecimalToBigInteger(Object from, Converter converter, Conve return ((BigDecimal)from).toBigInteger(); } + static BigDecimal bigDecimalToBigDecimal(Object from, Converter converter, ConverterOptions options) { + return new BigDecimal(from.toString()); + } + static AtomicBoolean toAtomicBoolean(Object from, Converter converter, ConverterOptions options) { return new AtomicBoolean(toLong(from) != 0); } @@ -129,6 +133,10 @@ static BigDecimal floatingPointToBigDecimal(Object from, Converter converter, Co return BigDecimal.valueOf(toDouble(from)); } + static BigInteger floatingPointToBigInteger(Object from, Converter converter, ConverterOptions options) { + return new BigInteger(String.format("%.0f", ((Number)from).doubleValue())); + } + static boolean isIntTypeNotZero(Object from, Converter converter, ConverterOptions options) { return toLong(from) != 0; } @@ -145,6 +153,11 @@ static boolean isBigDecimalNotZero(Object from, Converter converter, ConverterOp return ((BigDecimal)from).compareTo(BigDecimal.ZERO) != 0; } + static BigInteger toBigInteger(Object from, Converter converter, ConverterOptions options) { + return new BigInteger(from.toString()); + } + + /** * @param from Number instance to convert to char. * @return char that best represents the Number. The result will always be a value between @@ -175,8 +188,10 @@ static Date toDate(Object from, Converter converter, ConverterOptions options) { return new Date(toLong(from)); } + static Instant toInstant(Object from) { return Instant.ofEpochMilli(toLong(from)); } + static Instant toInstant(Object from, Converter converter, ConverterOptions options) { - return Instant.ofEpochMilli(toLong(from)); + return toInstant(from); } static java.sql.Date toSqlDate(Object from, Converter converter, ConverterOptions options) { @@ -188,18 +203,26 @@ static Timestamp toTimestamp(Object from, Converter converter, ConverterOptions } static Calendar toCalendar(Object from, Converter converter, ConverterOptions options) { - return CalendarConversion.create(toLong(from), options); + return CalendarConversions.create(toLong(from), options); } static LocalDate toLocalDate(Object from, Converter converter, ConverterOptions options) { - return Instant.ofEpochMilli(toLong(from)).atZone(options.getZoneId()).toLocalDate(); + return toZonedDateTime(from, options).toLocalDate(); } static LocalDateTime toLocalDateTime(Object from, Converter converter, ConverterOptions options) { - return Instant.ofEpochMilli(toLong(from)).atZone(options.getZoneId()).toLocalDateTime(); + return toZonedDateTime(from, options).toLocalDateTime(); + } + + static LocalTime toLocalTime(Object from, Converter converter, ConverterOptions options) { + return toZonedDateTime(from, options).toLocalTime(); + } + + static ZonedDateTime toZonedDateTime(Object from, ConverterOptions options) { + return toInstant(from).atZone(options.getZoneId()); } static ZonedDateTime toZonedDateTime(Object from, Converter converter, ConverterOptions options) { - return Instant.ofEpochMilli(toLong(from)).atZone(options.getZoneId()); + return toZonedDateTime(from, options); } } diff --git a/src/main/java/com/cedarsoftware/util/convert/StringConversion.java b/src/main/java/com/cedarsoftware/util/convert/StringConversions.java similarity index 85% rename from src/main/java/com/cedarsoftware/util/convert/StringConversion.java rename to src/main/java/com/cedarsoftware/util/convert/StringConversions.java index eb349f7e..a5638c3e 100644 --- a/src/main/java/com/cedarsoftware/util/convert/StringConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/StringConversions.java @@ -3,16 +3,15 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; +import java.sql.Timestamp; +import java.time.Instant; 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; +import com.cedarsoftware.util.StringUtilities; /** * @author John DeRegnaucourt (jdereg@gmail.com) @@ -31,7 +30,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -public class StringConversion { +public class StringConversions { private static final BigDecimal bigDecimalMinByte = BigDecimal.valueOf(Byte.MIN_VALUE); private static final BigDecimal bigDecimalMaxByte = BigDecimal.valueOf(Byte.MAX_VALUE); private static final BigDecimal bigDecimalMinShort = BigDecimal.valueOf(Short.MIN_VALUE); @@ -188,7 +187,7 @@ static AtomicInteger toAtomicInteger(Object from, Converter converter, Converter } static AtomicLong toAtomicLong(Object from, Converter converter, ConverterOptions options) { - String str = ((String) from).trim(); + String str = StringUtilities.trimToEmpty((String)from); if (str.isEmpty()) { return new AtomicLong(0L); } @@ -200,7 +199,7 @@ static AtomicLong toAtomicLong(Object from, Converter converter, ConverterOption } static Boolean toBoolean(Object from, Converter converter, ConverterOptions options) { - String str = ((String) from).trim(); + String str = StringUtilities.trimToEmpty((String)from); if (str.isEmpty()) { return false; } @@ -210,11 +209,11 @@ static Boolean toBoolean(Object from, Converter converter, ConverterOptions opti } else if ("false".equals(str)) { return false; } - return "true".equalsIgnoreCase(str) || "t".equalsIgnoreCase(str) || "1".equalsIgnoreCase(str); + return "true".equalsIgnoreCase(str) || "t".equalsIgnoreCase(str) || "1".equalsIgnoreCase(str) || "y".equalsIgnoreCase(str); } static char toCharacter(Object from, Converter converter, ConverterOptions options) { - String str = ((String) from); + String str = StringUtilities.trimToEmpty((String)from); if (str.isEmpty()) { return (char) 0; } @@ -226,7 +225,7 @@ static char toCharacter(Object from, Converter converter, ConverterOptions optio } static BigInteger toBigInteger(Object from, Converter converter, ConverterOptions options) { - String str = ((String) from).trim(); + String str = StringUtilities.trimToEmpty((String)from); if (str.isEmpty()) { return BigInteger.ZERO; } @@ -239,7 +238,7 @@ static BigInteger toBigInteger(Object from, Converter converter, ConverterOption } static BigDecimal toBigDecimal(Object from, Converter converter, ConverterOptions options) { - String str = ((String) from).trim(); + String str = StringUtilities.trimToEmpty((String)from); if (str.isEmpty()) { return BigDecimal.ZERO; } @@ -251,11 +250,34 @@ static BigDecimal toBigDecimal(Object from, Converter converter, ConverterOption } static java.sql.Date toSqlDate(Object from, Converter converter, ConverterOptions options) { - String str = ((String) from).trim(); + String str = StringUtilities.trimToNull((String)from); Date date = DateUtilities.parseDate(str); - if (date == null) { + return date == null ? null : new java.sql.Date(date.getTime()); + } + + static Timestamp toTimestamp(Object from, Converter converter, ConverterOptions options) { + String str = StringUtilities.trimToNull((String)from); + Date date = DateUtilities.parseDate(str); + return date == null ? null : new Timestamp(date.getTime()); + } + + static Date toDate(Object from, Converter converter, ConverterOptions options) { + String str = StringUtilities.trimToNull((String)from); + Date date = DateUtilities.parseDate(str); + return date; + } + + static Instant toInstant(Object from, Converter converter, ConverterOptions options) { + String s = StringUtilities.trimToEmpty((String)from); + if (s.isEmpty()) { return null; } - return new java.sql.Date(date.getTime()); + + try { + return Instant.parse(s); + } catch (Exception e) { + Date date = DateUtilities.parseDate(s); + return date == null ? null : date.toInstant(); + } } } diff --git a/src/main/java/com/cedarsoftware/util/convert/UUIDConversions.java b/src/main/java/com/cedarsoftware/util/convert/UUIDConversions.java new file mode 100644 index 00000000..cc7b4567 --- /dev/null +++ b/src/main/java/com/cedarsoftware/util/convert/UUIDConversions.java @@ -0,0 +1,28 @@ +package com.cedarsoftware.util.convert; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.UUID; + +public final class UUIDConversions { + + private UUIDConversions() { + } + + static BigDecimal toBigDecimal(Object from, Converter converter, ConverterOptions options) { + UUID uuid = (UUID) from; + BigInteger mostSignificant = BigInteger.valueOf(uuid.getMostSignificantBits()); + BigInteger leastSignificant = BigInteger.valueOf(uuid.getLeastSignificantBits()); + // Shift the most significant bits to the left and add the least significant bits + return new BigDecimal(mostSignificant.shiftLeft(64).add(leastSignificant)); + } + + static BigInteger toBigInteger(Object from, Converter converter, ConverterOptions options) { + UUID uuid = (UUID) from; + BigInteger mostSignificant = BigInteger.valueOf(uuid.getMostSignificantBits()); + BigInteger leastSignificant = BigInteger.valueOf(uuid.getLeastSignificantBits()); + // Shift the most significant bits to the left and add the least significant bits + return mostSignificant.shiftLeft(64).add(leastSignificant); + } +} + diff --git a/src/main/java/com/cedarsoftware/util/convert/VoidConversion.java b/src/main/java/com/cedarsoftware/util/convert/VoidConversions.java similarity index 94% rename from src/main/java/com/cedarsoftware/util/convert/VoidConversion.java rename to src/main/java/com/cedarsoftware/util/convert/VoidConversions.java index 6ca23ae2..08218952 100644 --- a/src/main/java/com/cedarsoftware/util/convert/VoidConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/VoidConversions.java @@ -17,7 +17,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -public class VoidConversion { +public final class VoidConversions { + + private VoidConversions() { + } static Object toNull(Object from, Converter converter, ConverterOptions options) { return null; diff --git a/src/main/java/com/cedarsoftware/util/convert/ZonedDateTimeConversion.java b/src/main/java/com/cedarsoftware/util/convert/ZonedDateTimeConversions.java similarity index 95% rename from src/main/java/com/cedarsoftware/util/convert/ZonedDateTimeConversion.java rename to src/main/java/com/cedarsoftware/util/convert/ZonedDateTimeConversions.java index 1a765188..4395d4bb 100644 --- a/src/main/java/com/cedarsoftware/util/convert/ZonedDateTimeConversion.java +++ b/src/main/java/com/cedarsoftware/util/convert/ZonedDateTimeConversions.java @@ -12,7 +12,7 @@ import java.util.Date; import java.util.concurrent.atomic.AtomicLong; -public class ZonedDateTimeConversion { +public class ZonedDateTimeConversions { static ZonedDateTime toDifferentZone(Object fromInstance, ConverterOptions options) { return ((ZonedDateTime)fromInstance).withZoneSameInstant(options.getZoneId()); @@ -55,7 +55,7 @@ static Timestamp toTimestamp(Object fromInstance, Converter converter, Converter } static Calendar toCalendar(Object fromInstance, Converter converter, ConverterOptions options) { - return CalendarConversion.create(toLong(fromInstance), options); + return CalendarConversions.create(toLong(fromInstance), options); } static java.sql.Date toSqlDate(Object fromInstance, Converter converter, ConverterOptions options) { diff --git a/src/test/java/com/cedarsoftware/util/ClassUtilitiesTest.java b/src/test/java/com/cedarsoftware/util/ClassUtilitiesTest.java index 6f5bdbb2..226bee16 100644 --- a/src/test/java/com/cedarsoftware/util/ClassUtilitiesTest.java +++ b/src/test/java/com/cedarsoftware/util/ClassUtilitiesTest.java @@ -152,4 +152,75 @@ public void testPrimitives() { assert 1 == ClassUtilities.computeInheritanceDistance(java.sql.Date.class, Date.class); } + @Test + public void testClassForName() + { + Class testObjectClass = ClassUtilities.forName(SubClass.class.getName(), ClassUtilities.class.getClassLoader()); + assert testObjectClass instanceof Class; + assert SubClass.class.getName().equals(testObjectClass.getName()); + } + + @Test + public void testClassForNameWithClassloader() + { + Class testObjectClass = ClassUtilities.forName("ReallyLong", new AlternateNameClassLoader("ReallyLong", Long.class)); + assert testObjectClass instanceof Class; + assert "java.lang.Long".equals(testObjectClass.getName()); + } + + @Test + public void testClassForNameNullClassErrorHandling() + { + assert null == ClassUtilities.forName(null, ClassUtilities.class.getClassLoader()); + assert null == ClassUtilities.forName("Smith&Wesson", ClassUtilities.class.getClassLoader()); + } + + @Test + public void testClassForNameFailOnClassLoaderErrorTrue() + { + assert null == ClassUtilities.forName("foo.bar.baz.Qux", ClassUtilities.class.getClassLoader()); + } + + @Test + public void testClassForNameFailOnClassLoaderErrorFalse() + { + Class testObjectClass = ClassUtilities.forName("foo.bar.baz.Qux", ClassUtilities.class.getClassLoader()); + assert testObjectClass == null; + } + + private static class AlternateNameClassLoader extends ClassLoader + { + AlternateNameClassLoader(String alternateName, Class clazz) + { + super(AlternateNameClassLoader.class.getClassLoader()); + this.alternateName = alternateName; + this.clazz = clazz; + } + + public Class loadClass(String className) throws ClassNotFoundException + { + return findClass(className); + } + + protected Class findClass(String className) + { + try + { + return findSystemClass(className); + } + catch (Exception ignored) + { } + + if (alternateName.equals(className)) + { + return Long.class; + } + + return null; + } + + private final String alternateName; + private final Class clazz; + } + } diff --git a/src/test/java/com/cedarsoftware/util/CollectionUtilitiesTests.java b/src/test/java/com/cedarsoftware/util/CollectionUtilitiesTests.java new file mode 100644 index 00000000..79fa70b3 --- /dev/null +++ b/src/test/java/com/cedarsoftware/util/CollectionUtilitiesTests.java @@ -0,0 +1,105 @@ +package com.cedarsoftware.util; + +import com.cedarsoftware.util.io.MetaUtils; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class CollectionUtilitiesTests { + static class Rec { + final String s; + final int i; + Rec(String s, int i) { + this.s = s; + this.i = i; + } + + Rec link; + List ilinks; + List mlinks; + + Map smap; + } + + @Test + void testListOf() { + final List list = CollectionUtilities.listOf(); + assertEquals(0, list.size()); + } + + @Test + void testListOf_producesImmutableList() { + final List list = CollectionUtilities.listOf(); + assertThatExceptionOfType(UnsupportedOperationException.class) + .isThrownBy(() -> list.add("One")); + } + + @Test + void testListOfOne() { + final List list = CollectionUtilities.listOf("One"); + assertEquals(1, list.size()); + assertEquals("One", list.get(0)); + } + + @Test + void testListOfTwo() { + final List list = CollectionUtilities.listOf("One", "Two"); + assertEquals(2, list.size()); + assertEquals("One", list.get(0)); + assertEquals("Two", list.get(1)); + } + + @Test + void testListOfThree() { + final List list = CollectionUtilities.listOf("One", "Two", "Three"); + assertEquals(3, list.size()); + assertEquals("One", list.get(0)); + assertEquals("Two", list.get(1)); + assertEquals("Three", list.get(2)); + } + + @Test + void testSetOf() { + final Set set = CollectionUtilities.setOf(); + assertEquals(0, set.size()); + } + + @Test + void testSetOf_producesImmutableSet() { + final Set set = CollectionUtilities.setOf(); + assertThatExceptionOfType(UnsupportedOperationException.class) + .isThrownBy(() -> set.add("One")); + } + + + @Test + void testSetOfOne() { + final Set set = CollectionUtilities.setOf("One"); + assertEquals(1, set.size()); + assertTrue(set.contains("One")); + } + + @Test + public void testSetOfTwo() { + final Set set = CollectionUtilities.setOf("One", "Two"); + assertEquals(2, set.size()); + assertTrue(set.contains("One")); + assertTrue(set.contains("Two")); + } + + @Test + public void testSetOfThree() { + final Set set = CollectionUtilities.setOf("One", "Two", "Three"); + assertEquals(3, set.size()); + assertTrue(set.contains("One")); + assertTrue(set.contains("Two")); + assertTrue(set.contains("Three")); + } +} diff --git a/src/test/java/com/cedarsoftware/util/TestStringUtilities.java b/src/test/java/com/cedarsoftware/util/TestStringUtilities.java index cffc8833..7bd2c0a0 100644 --- a/src/test/java/com/cedarsoftware/util/TestStringUtilities.java +++ b/src/test/java/com/cedarsoftware/util/TestStringUtilities.java @@ -2,12 +2,24 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; +import java.nio.ByteBuffer; import java.util.Random; import java.util.Set; import java.util.TreeSet; +import java.util.stream.Stream; +import com.cedarsoftware.util.convert.CommonValues; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.mockito.internal.util.StringUtil; +import javax.swing.text.Segment; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -37,7 +49,7 @@ public class TestStringUtilities { @Test - public void testConstructorIsPrivate() throws Exception { + void testConstructorIsPrivate() throws Exception { Class c = StringUtilities.class; assertEquals(Modifier.FINAL, c.getModifiers() & Modifier.FINAL); @@ -48,6 +60,111 @@ public void testConstructorIsPrivate() throws Exception { assertNotNull(con.newInstance()); } + @ParameterizedTest + @MethodSource("stringsWithAllWhitespace") + void testIsEmpty_whenStringHasOnlyWhitespace_returnsTrue(String s) + { + assertTrue(StringUtilities.isEmpty(s)); + } + + @ParameterizedTest + @MethodSource("stringsWithContentOtherThanWhitespace") + void testIsEmpty_whenStringHasContent_returnsFalse(String s) + { + assertFalse(StringUtilities.isEmpty(s)); + } + + @ParameterizedTest + @NullAndEmptySource + void testIsEmpty_whenNullOrEmpty_returnsTrue(String s) + { + assertTrue(StringUtilities.isEmpty(s)); + } + + @ParameterizedTest + @MethodSource("stringsWithAllWhitespace") + void testIsNotEmpty_whenStringHasOnlyWhitespace_returnsFalse(String s) + { + assertFalse(StringUtilities.isNotEmpty(s)); + } + + @ParameterizedTest + @MethodSource("stringsWithContentOtherThanWhitespace") + void testIsNotEmpty_whenStringHasContent_returnsTrue(String s) + { + assertTrue(StringUtilities.isNotEmpty(s)); + } + + @ParameterizedTest + @NullAndEmptySource + void testIsNotEmpty_whenNullOrEmpty_returnsFalse(String s) + { + assertFalse(StringUtilities.isNotEmpty(s)); + } + + @ParameterizedTest + @MethodSource("stringsWithAllWhitespace") + void testIsWhiteSpace_whenStringHasWhitespace_returnsTrue(String s) + { + assertTrue(StringUtilities.isWhitespace(s)); + } + + @ParameterizedTest + @MethodSource("stringsWithContentOtherThanWhitespace") + void testIsWhiteSpace_whenStringHasContent_returnsFalse(String s) + { + assertFalse(StringUtilities.isWhitespace(s)); + } + + @ParameterizedTest + @NullAndEmptySource + void testIsWhiteSpace_whenNullOrEmpty_returnsTrue(String s) + { + assertTrue(StringUtilities.isWhitespace(s)); + } + + + @ParameterizedTest + @MethodSource("stringsWithAllWhitespace") + void testHasContent_whenStringHasWhitespace_returnsFalse(String s) + { + assertFalse(StringUtilities.hasContent(s)); + } + + @ParameterizedTest + @MethodSource("stringsWithContentOtherThanWhitespace") + void testHasContent_whenStringHasContent_returnsTrue(String s) + { + assertTrue(StringUtilities.hasContent(s)); + } + + @ParameterizedTest + @NullAndEmptySource + void testHasContent_whenNullOrEmpty_returnsFalse(String s) + { + assertFalse(StringUtilities.hasContent(s)); + } + + @ParameterizedTest + @MethodSource("stringsWithAllWhitespace") + void testIsNotWhitespace_whenStringHasWhitespace_returnsFalse(String s) + { + assertFalse(StringUtilities.isNotWhitespace(s)); + } + + @ParameterizedTest + @MethodSource("stringsWithContentOtherThanWhitespace") + void testIsNotWhitespace_whenStringHasContent_returnsTrue(String s) + { + assertTrue(StringUtilities.isNotWhitespace(s)); + } + + @ParameterizedTest + @NullAndEmptySource + void testIsNotWhitespace_whenNullOrEmpty_returnsFalse(String s) + { + assertFalse(StringUtilities.isNotWhitespace(s)); + } @Test public void testIsEmpty() { @@ -57,14 +174,14 @@ public void testIsEmpty() } @Test - public void testHasContent() { + void testHasContent() { assertFalse(StringUtilities.hasContent(null)); assertFalse(StringUtilities.hasContent("")); assertTrue(StringUtilities.hasContent("foo")); } @Test - public void testTrimLength() { + void testTrimLength() { assertEquals(0, StringUtilities.trimLength(null)); assertEquals(0, StringUtilities.trimLength("")); assertEquals(3, StringUtilities.trimLength(" abc ")); @@ -75,7 +192,7 @@ public void testTrimLength() { } @Test - public void testEqualsWithTrim() { + void testEqualsWithTrim() { assertTrue(StringUtilities.equalsWithTrim("abc", " abc ")); assertTrue(StringUtilities.equalsWithTrim(" abc ", "abc")); assertFalse(StringUtilities.equalsWithTrim("abc", " AbC ")); @@ -86,7 +203,7 @@ public void testEqualsWithTrim() { } @Test - public void testEqualsIgnoreCaseWithTrim() { + void testEqualsIgnoreCaseWithTrim() { assertTrue(StringUtilities.equalsIgnoreCaseWithTrim("abc", " abc ")); assertTrue(StringUtilities.equalsIgnoreCaseWithTrim(" abc ", "abc")); assertTrue(StringUtilities.equalsIgnoreCaseWithTrim("abc", " AbC ")); @@ -97,7 +214,7 @@ public void testEqualsIgnoreCaseWithTrim() { } @Test - public void testCount() { + void testCount() { assertEquals(2, StringUtilities.count("abcabc", 'a')); assertEquals(0, StringUtilities.count("foo", 'a')); assertEquals(0, StringUtilities.count(null, 'a')); @@ -105,7 +222,7 @@ public void testCount() { } @Test - public void testString() + void testString() { assertTrue(StringUtilities.isEmpty(null)); assertFalse(StringUtilities.hasContent(null)); @@ -118,12 +235,12 @@ public void testString() } @Test - public void testEncode() { + void testEncode() { assertEquals("1A", StringUtilities.encode(new byte[]{0x1A})); assertEquals("", StringUtilities.encode(new byte[]{})); } - public void testEncodeWithNull() + void testEncodeWithNull() { try { @@ -136,13 +253,13 @@ public void testEncodeWithNull() } @Test - public void testDecode() { + void testDecode() { assertArrayEquals(new byte[]{0x1A}, StringUtilities.decode("1A")); assertArrayEquals(new byte[]{}, StringUtilities.decode("")); assertNull(StringUtilities.decode("1AB")); } - public void testDecodeWithNull() + void testDecodeWithNull() { try { @@ -154,31 +271,174 @@ public void testDecodeWithNull() } } - @Test - public void testEquals() + + private static Stream charSequenceEquals_caseSensitive() { + return Stream.of( + Arguments.of(null, null), + Arguments.of("", ""), + Arguments.of("foo", "foo"), + Arguments.of(new StringBuffer("foo"), "foo"), + Arguments.of(new StringBuilder("foo"), "foo"), + Arguments.of(new Segment("foobar".toCharArray(), 0, 3), "foo") + ); + } + + + + @ParameterizedTest + @MethodSource("charSequenceEquals_caseSensitive") + void testEquals_whenStringsAreEqualCaseSensitive_returnsTrue(CharSequence one, CharSequence two) + { + assertThat(StringUtilities.equals(one, two)).isTrue(); + } + + private static Stream charSequenceNotEqual_caseSensitive() { + return Stream.of( + Arguments.of(null, ""), + Arguments.of("", null), + Arguments.of("foo", "bar"), + Arguments.of(" foo", "bar"), + Arguments.of("foO", "foo"), + Arguments.of("foo", "food"), + Arguments.of(new StringBuffer("foo"), "bar"), + Arguments.of(new StringBuffer("foo"), " foo"), + Arguments.of(new StringBuffer("foO"), "foo"), + Arguments.of(new StringBuilder("foo"), "bar"), + Arguments.of(new StringBuilder("foo"), " foo "), + Arguments.of(new StringBuilder("foO"), "foo"), + Arguments.of(new Segment("foobar".toCharArray(), 0, 3), "bar"), + Arguments.of(new Segment(" foo ".toCharArray(), 0, 5), "bar"), + Arguments.of(new Segment("FOOBAR".toCharArray(), 0, 3), "foo") + ); + } + @ParameterizedTest + @MethodSource("charSequenceNotEqual_caseSensitive") + void testEquals_whenStringsAreNotEqualCaseSensitive_returnsFalse(CharSequence one, CharSequence two) + { + assertThat(StringUtilities.equals(one, two)).isFalse(); + } + + private static Stream charSequenceEquals_ignoringCase() { + return Stream.of( + Arguments.of(null, null), + Arguments.of("", ""), + Arguments.of("foo", "foo"), + Arguments.of("FOO", "foo"), + Arguments.of(new StringBuffer("foo"), "foo"), + Arguments.of(new StringBuffer("FOO"), "foo"), + Arguments.of(new StringBuilder("foo"), "foo"), + Arguments.of(new StringBuilder("FOO"), "foo"), + Arguments.of(new Segment("foobar".toCharArray(), 0, 3), "foo"), + Arguments.of(new Segment("FOOBAR".toCharArray(), 0, 3), "foo") + ); + } + + @ParameterizedTest + @MethodSource("charSequenceEquals_ignoringCase") + void testEqualsIgnoreCase_whenStringsAreEqualIgnoringCase_returnsTrue(CharSequence one, CharSequence two) { - assertTrue(StringUtilities.equals(null, null)); - assertFalse(StringUtilities.equals(null, "")); - assertFalse(StringUtilities.equals("", null)); - assertFalse(StringUtilities.equals("foo", "bar")); - assertFalse(StringUtilities.equals("Foo", "foo")); - assertTrue(StringUtilities.equals("foo", "foo")); + assertThat(StringUtilities.equalsIgnoreCase(one, two)).isTrue(); + } + + private static Stream charSequenceNotEqual_ignoringCase() { + return Stream.of( + Arguments.of(null, ""), + Arguments.of("", null), + Arguments.of("foo", "bar"), + Arguments.of(" foo ", "foo"), + Arguments.of(" foo ", "food"), + Arguments.of(" foo ", "foo"), + Arguments.of(new StringBuffer("foo"), "bar"), + Arguments.of(new StringBuffer("foo "), "foo"), + Arguments.of(new StringBuilder("foo"), "bar"), + Arguments.of(new StringBuilder("foo "), "foo"), + Arguments.of(new Segment("foobar".toCharArray(), 0, 3), "bar"), + Arguments.of(new Segment("foo bar".toCharArray(), 0, 4), "foo") + ); + } + + @ParameterizedTest + @MethodSource("charSequenceNotEqual_ignoringCase") + void testEqualsIgnoreCase_whenStringsAreNotEqualIgnoringCase_returnsFalse(CharSequence one, CharSequence two) + { + assertThat(StringUtilities.equalsIgnoreCase(one, two)).isFalse(); } - @Test - public void testEqualsIgnoreCase() + private static Stream charSequenceEquals_afterTrimCaseSensitive() { + return Stream.of( + Arguments.of(null, null), + Arguments.of("", ""), + Arguments.of("foo", "foo"), + Arguments.of(" foo", "foo"), + Arguments.of("foo\r\n", "foo"), + Arguments.of("foo ", "\tfoo ") + ); + } + + @ParameterizedTest + @MethodSource("charSequenceEquals_afterTrimCaseSensitive") + void testEqualsWithTrim_whenStringsAreEqual_afterTrimCaseSensitive_returnsTrue(String one, String two) + { + assertThat(StringUtilities.equalsWithTrim(one, two)).isTrue(); + } + + private static Stream charSequenceNotEqual_afterTrimCaseSensitive() { + return Stream.of( + Arguments.of(null, ""), + Arguments.of("", null), + Arguments.of("foo", "bar"), + Arguments.of("F00", "foo"), + Arguments.of("food", "foo"), + Arguments.of("foo", "food") + + ); + } + + @ParameterizedTest + @MethodSource("charSequenceNotEqual_afterTrimCaseSensitive") + void testEqualsWithTrim_whenStringsAreNotEqual_returnsFalse(String one, String two) { - assertTrue(StringUtilities.equalsIgnoreCase(null, null)); - assertFalse(StringUtilities.equalsIgnoreCase(null, "")); - assertFalse(StringUtilities.equalsIgnoreCase("", null)); - assertFalse(StringUtilities.equalsIgnoreCase("foo", "bar")); - assertTrue(StringUtilities.equalsIgnoreCase("Foo", "foo")); - assertTrue(StringUtilities.equalsIgnoreCase("foo", "foo")); + assertThat(StringUtilities.equalsWithTrim(one, two)).isFalse(); } + private static Stream charSequenceEquals_afterTrimAndIgnoringCase() { + return Stream.of( + Arguments.of(null, null), + Arguments.of("", ""), + Arguments.of("foo", "foo"), + Arguments.of(" foo", "foo"), + Arguments.of("foo\r\n", "foo"), + Arguments.of("foo ", "\tfoo "), + Arguments.of("FOO", "foo") + ); + } + + @ParameterizedTest + @MethodSource("charSequenceEquals_afterTrimAndIgnoringCase") + void testEqualsIgnoreCaseWithTrim_whenStringsAreEqual_caseSensitive_returnsTrue(String one, String two) + { + assertThat(StringUtilities.equalsIgnoreCaseWithTrim(one, two)).isTrue(); + } + + private static Stream charSequenceNotEqual_afterTrimIgnoringCase() { + return Stream.of( + Arguments.of(null, ""), + Arguments.of("", null), + Arguments.of("foo", "bar"), + Arguments.of("foo", "food") + + ); + } + + @ParameterizedTest + @MethodSource("charSequenceNotEqual_afterTrimIgnoringCase") + void testEqualsIgnoreCaseWithTrim_whenStringsAreNotEqualIgnoringCase_returnsFalse(String one, String two) + { + assertThat(StringUtilities.equalsIgnoreCaseWithTrim(one, two)).isFalse(); + } @Test - public void testLastIndexOf() + void testLastIndexOf() { assertEquals(-1, StringUtilities.lastIndexOf(null, 'a')); assertEquals(-1, StringUtilities.lastIndexOf("foo", 'a')); @@ -186,7 +446,7 @@ public void testLastIndexOf() } @Test - public void testLength() + void testLength() { assertEquals(0, StringUtilities.length("")); assertEquals(0, StringUtilities.length(null)); @@ -194,7 +454,7 @@ public void testLength() } @Test - public void testLevenshtein() + void testLevenshtein() { assertEquals(3, StringUtilities.levenshteinDistance("example", "samples")); assertEquals(6, StringUtilities.levenshteinDistance("sturgeon", "urgently")); @@ -214,7 +474,7 @@ public void testLevenshtein() } @Test - public void testDamerauLevenshtein() throws Exception + void testDamerauLevenshtein() throws Exception { assertEquals(3, StringUtilities.damerauLevenshteinDistance("example", "samples")); assertEquals(6, StringUtilities.damerauLevenshteinDistance("sturgeon", "urgently")); @@ -239,7 +499,7 @@ public void testDamerauLevenshtein() throws Exception } @Test - public void testRandomString() + void testRandomString() { Random random = new Random(42); Set strings = new TreeSet(); @@ -255,7 +515,7 @@ public void testRandomString() } } - public void testGetBytesWithInvalidEncoding() { + void testGetBytesWithInvalidEncoding() { try { StringUtilities.getBytes("foo", "foo"); @@ -267,31 +527,31 @@ public void testGetBytesWithInvalidEncoding() { } @Test - public void testGetBytes() + void testGetBytes() { assertArrayEquals(new byte[]{102, 111, 111}, StringUtilities.getBytes("foo", "UTF-8")); } @Test - public void testGetUTF8Bytes() + void testGetUTF8Bytes() { assertArrayEquals(new byte[]{102, 111, 111}, StringUtilities.getUTF8Bytes("foo")); } @Test - public void testGetBytesWithNull() + void testGetBytesWithNull() { assert StringUtilities.getBytes(null, "UTF-8") == null; } @Test - public void testGetBytesWithEmptyString() + void testGetBytesWithEmptyString() { assert DeepEquals.deepEquals(new byte[]{}, StringUtilities.getBytes("", "UTF-8")); } @Test - public void testWildcard() + void testWildcard() { String name = "George Washington"; assertTrue(name.matches(StringUtilities.wildcardToRegexString("*"))); @@ -309,37 +569,37 @@ public void testWildcard() } @Test - public void testCreateString() + void testCreateString() { assertEquals("foo", StringUtilities.createString(new byte[]{102, 111, 111}, "UTF-8")); } @Test - public void testCreateUTF8String() + void testCreateUTF8String() { assertEquals("foo", StringUtilities.createUTF8String(new byte[]{102, 111, 111})); } @Test - public void testCreateStringWithNull() + void testCreateStringWithNull() { assertNull(null, StringUtilities.createString(null, "UTF-8")); } @Test - public void testCreateStringWithEmptyArray() + void testCreateStringWithEmptyArray() { assertEquals("", StringUtilities.createString(new byte[]{}, "UTF-8")); } @Test - public void testCreateUTF8StringWithEmptyArray() + void testCreateUTF8StringWithEmptyArray() { assertEquals("", StringUtilities.createUTF8String(new byte[]{})); } @Test - public void testCreateStringWithInvalidEncoding() + void testCreateStringWithInvalidEncoding() { try { @@ -351,25 +611,25 @@ public void testCreateStringWithInvalidEncoding() } @Test - public void testCreateUtf8String() + void testCreateUtf8String() { assertEquals("foo", StringUtilities.createUtf8String(new byte[] {102, 111, 111})); } @Test - public void testCreateUtf8StringWithNull() + void testCreateUtf8StringWithNull() { assertNull(null, StringUtilities.createUtf8String(null)); } @Test - public void testCreateUtf8StringWithEmptyArray() + void testCreateUtf8StringWithEmptyArray() { assertEquals("", StringUtilities.createUtf8String(new byte[]{})); } @Test - public void testHashCodeIgnoreCase() + void testHashCodeIgnoreCase() { String s = "Hello"; String t = "HELLO"; @@ -383,7 +643,14 @@ public void testHashCodeIgnoreCase() } @Test - public void testCount2() + void testGetBytes_withInvalidEncoding_throwsException() { + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> StringUtilities.getBytes("Some text", "foo-bar")) + .withMessageContaining("Encoding (foo-bar) is not supported"); + } + + @Test + void testCount2() { assert 0 == StringUtilities.count("alphabet", null); assert 0 == StringUtilities.count(null, "al"); @@ -392,4 +659,138 @@ public void testCount2() assert 1 == StringUtilities.count("alphabet", "al"); assert 2 == StringUtilities.count("halal", "al"); } + + private static Stream stringsWithAllWhitespace() { + return Stream.of( + Arguments.of(" "), + Arguments.of(" \t "), + Arguments.of("\r\n ") + ); + } + + private static Stream stringsWithContentOtherThanWhitespace() { + return Stream.of( + Arguments.of("jfk"), + Arguments.of(" jfk\r\n"), + Arguments.of("\tjfk "), + Arguments.of(" jfk ") + ); + } + + @ParameterizedTest + @NullAndEmptySource + void testTrimToEmpty_whenNullOrEmpty_returnsEmptyString(String value) { + assertThat(StringUtilities.trimToEmpty(value)).isEqualTo(StringUtilities.EMPTY); + } + + @ParameterizedTest + @MethodSource("stringsWithAllWhitespace") + void testTrimToEmpty_whenStringIsAllWhitespace_returnsEmptyString(String value) { + assertThat(StringUtilities.trimToEmpty(value)).isEqualTo(StringUtilities.EMPTY); + } + + @ParameterizedTest + @MethodSource("stringsWithContentOtherThanWhitespace") + void testTrimToEmpty_whenStringHasContent_returnsTrimmedString(String value) { + assertThat(StringUtilities.trimToEmpty(value)).isEqualTo(value.trim()); + } + + @ParameterizedTest + @NullAndEmptySource + void testTrimToNull_whenNullOrEmpty_returnsNull(String value) { + assertThat(StringUtilities.trimToNull(value)).isNull(); + } + + @ParameterizedTest + @MethodSource("stringsWithAllWhitespace") + void testTrimToNull_whenStringIsAllWhitespace_returnsNull(String value) { + assertThat(StringUtilities.trimToNull(value)).isNull(); + } + + @ParameterizedTest + @MethodSource("stringsWithContentOtherThanWhitespace") + void testTrimToNull_whenStringHasContent_returnsTrimmedString(String value) { + assertThat(StringUtilities.trimToNull(value)).isEqualTo(value.trim()); + } + + @ParameterizedTest + @NullAndEmptySource + void testTrimToDefault_whenNullOrEmpty_returnsDefault(String value) { + assertThat(StringUtilities.trimEmptyToDefault(value, "foo")).isEqualTo("foo"); + } + + @ParameterizedTest + @MethodSource("stringsWithAllWhitespace") + void testTrimToDefault_whenStringIsAllWhitespace_returnsDefault(String value) { + assertThat(StringUtilities.trimEmptyToDefault(value, "foo")).isEqualTo("foo"); + } + + @ParameterizedTest + @MethodSource("stringsWithContentOtherThanWhitespace") + void testTrimToDefault_whenStringHasContent_returnsTrimmedString(String value) { + assertThat(StringUtilities.trimEmptyToDefault(value, "foo")).isEqualTo(value.trim()); + } + + + private static Stream regionMatches_returnsTrue() { + return Stream.of( + Arguments.of("a", true, 0, "abc", 0, 0), + Arguments.of("a", true, 0, "abc", 0, 1), + Arguments.of("Abc", true, 0, "abc", 0, 3), + Arguments.of("Abc", true, 1, "abc", 1, 2), + Arguments.of("Abc", false, 1, "abc", 1, 2), + Arguments.of("Abcd", true, 1, "abcD", 1, 2), + Arguments.of("Abcd", false, 1, "abcD", 1, 2), + Arguments.of(new StringBuilder("a"), true, 0, new StringBuffer("abc"), 0, 0), + Arguments.of(new StringBuilder("a"), true, 0, new StringBuffer("abc"), 0, 1), + Arguments.of(new StringBuilder("Abc"), true, 0, new StringBuffer("abc"), 0, 3), + Arguments.of(new StringBuilder("Abc"), true, 1, new StringBuffer("abc"), 1, 2), + Arguments.of(new StringBuilder("Abc"), false, 1, new StringBuffer("abc"), 1, 2), + Arguments.of(new StringBuilder("Abcd"), true, 1, new StringBuffer("abcD"), 1, 2), + Arguments.of(new StringBuilder("Abcd"), false, 1, new StringBuffer("abcD"), 1, 2) + + ); + } + @ParameterizedTest + @MethodSource("regionMatches_returnsTrue") + void testRegionMatches_returnsTrue(CharSequence s, boolean ignoreCase, int start, CharSequence substring, int subStart, int length) { + boolean matches = StringUtilities.regionMatches(s, ignoreCase, start, substring, subStart, length); + assertThat(matches).isTrue(); + } + + private static Stream regionMatches_returnsFalse() { + return Stream.of( + Arguments.of("", true, -1, "", -1, -1), + Arguments.of("", true, 0, "", 0, 1), + Arguments.of("Abc", false, 0, "abc", 0, 3), + Arguments.of(new StringBuilder(""), true, -1, new StringBuffer(""), -1, -1), + Arguments.of(new StringBuilder(""), true, 0, new StringBuffer(""), 0, 1), + Arguments.of(new StringBuilder("Abc"), false, 0, new StringBuffer("abc"), 0, 3) + ); + } + + @ParameterizedTest + @MethodSource("regionMatches_returnsFalse") + void testRegionMatches_returnsFalse(CharSequence s, boolean ignoreCase, int start, CharSequence substring, int subStart, int length) { + boolean matches = StringUtilities.regionMatches(s, ignoreCase, start, substring, subStart, length); + assertThat(matches).isFalse(); + } + + + private static Stream regionMatches_throwsNullPointerException() { + return Stream.of( + Arguments.of("a", true, 0, null, 0, 0, "substring cannot be null"), + Arguments.of(null, true, 0, null, 0, 0, "cs to be processed cannot be null"), + Arguments.of(null, true, 0, "", 0, 0, "cs to be processed cannot be null") + ); + } + + @ParameterizedTest + @MethodSource("regionMatches_throwsNullPointerException") + void testRegionMatches_withStrings_throwsIllegalArgumentException(CharSequence s, boolean ignoreCase, int start, CharSequence substring, int subStart, int length, String exText) { + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> StringUtilities.regionMatches(s, ignoreCase, start, substring, subStart, length)) + .withMessageContaining(exText); + } + } diff --git a/src/test/java/com/cedarsoftware/util/convert/AtomicBooleanConversionsTests.java b/src/test/java/com/cedarsoftware/util/convert/AtomicBooleanConversionsTests.java new file mode 100644 index 00000000..e574e5b2 --- /dev/null +++ b/src/test/java/com/cedarsoftware/util/convert/AtomicBooleanConversionsTests.java @@ -0,0 +1,210 @@ +package com.cedarsoftware.util.convert; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Stream; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.assertj.core.api.Assertions.assertThat; + +class AtomicBooleanConversionsTests { + + private static Stream toByteParams() { + return Stream.of( + Arguments.of(true, CommonValues.BYTE_ONE), + Arguments.of(false, CommonValues.BYTE_ZERO) + ); + } + + @ParameterizedTest + @MethodSource("toByteParams") + void testToByte(boolean value, Byte expected) { + Byte actual = AtomicBooleanConversions.toByte(new AtomicBoolean(value), null, null); + assertThat(actual).isSameAs(expected); + } + + private static Stream toShortParams() { + return Stream.of( + Arguments.of(true, CommonValues.SHORT_ONE), + Arguments.of(false, CommonValues.SHORT_ZERO) + ); + } + + @ParameterizedTest + @MethodSource("toShortParams") + void testToShort(boolean value, Short expected) { + Short actual = AtomicBooleanConversions.toShort(new AtomicBoolean(value), null, null); + assertThat(actual).isSameAs(expected); + } + + private static Stream toIntegerParams() { + return Stream.of( + Arguments.of(true, CommonValues.INTEGER_ONE), + Arguments.of(false, CommonValues.INTEGER_ZERO) + ); + } + + @ParameterizedTest + @MethodSource("toIntegerParams") + void testToInteger(boolean value, Integer expected) { + Integer actual = AtomicBooleanConversions.toInteger(new AtomicBoolean(value), null, null); + assertThat(actual).isSameAs(expected); + } + + private static Stream toLongParams() { + return Stream.of( + Arguments.of(true, CommonValues.LONG_ONE), + Arguments.of(false, CommonValues.LONG_ZERO) + ); + } + + @ParameterizedTest + @MethodSource("toLongParams") + void testToLong(boolean value, long expected) { + long actual = AtomicBooleanConversions.toLong(new AtomicBoolean(value), null, null); + assertThat(actual).isSameAs(expected); + } + + private static Stream toFloatParams() { + return Stream.of( + Arguments.of(true, CommonValues.FLOAT_ONE), + Arguments.of(false, CommonValues.FLOAT_ZERO) + ); + } + + @ParameterizedTest + @MethodSource("toFloatParams") + void testToFloat(boolean value, Float expected) { + Float actual = AtomicBooleanConversions.toFloat(new AtomicBoolean(value), null, null); + assertThat(actual).isSameAs(expected); + } + + + private static Stream toDoubleParams() { + return Stream.of( + Arguments.of(true, CommonValues.DOUBLE_ONE), + Arguments.of(false, CommonValues.DOUBLE_ZERO) + ); + } + + @ParameterizedTest + @MethodSource("toDoubleParams") + void testToDouble(boolean value, Double expected) { + Double actual = AtomicBooleanConversions.toDouble(new AtomicBoolean(value), null, null); + assertThat(actual).isSameAs(expected); + } + + + private static Stream toBooleanParams() { + return Stream.of( + Arguments.of(true), + Arguments.of(false) + ); + } + + @ParameterizedTest + @MethodSource("toBooleanParams") + void testToBoolean(boolean value) { + boolean actual = AtomicBooleanConversions.toBoolean(new AtomicBoolean(value), null, null); + assertThat(actual).isSameAs(Boolean.valueOf(value)); + } + + @ParameterizedTest + @MethodSource("toIntegerParams") + void testToAtomicInteger(boolean value, int integer) { + AtomicInteger expected = new AtomicInteger(integer);; + AtomicInteger actual = AtomicBooleanConversions.toAtomicInteger(new AtomicBoolean(value), null, null); + assertThat(actual.get()).isEqualTo(expected.get()); + } + + @ParameterizedTest + @MethodSource("toLongParams") + void testToAtomicLong(boolean value, long expectedLong) { + AtomicLong expected = new AtomicLong(expectedLong); + AtomicLong actual = AtomicBooleanConversions.toAtomicLong(new AtomicBoolean(value), null, null); + assertThat(actual.get()).isEqualTo(expected.get()); + } + + private static Stream toCharacter_withDefaultParams() { + return Stream.of( + Arguments.of(true, CommonValues.CHARACTER_ONE), + Arguments.of(false, CommonValues.CHARACTER_ZERO) + ); + } + + @ParameterizedTest + @MethodSource("toCharacter_withDefaultParams") + void testToCharacter_withDefaultParams(boolean value, char expected) { + ConverterOptions options = createConvertOptions(CommonValues.CHARACTER_ONE, CommonValues.CHARACTER_ZERO); + Character actual = AtomicBooleanConversions.toCharacter(new AtomicBoolean(value), null, options); + assertThat(actual).isSameAs(expected); + } + + private static Stream toCharacterCustomParams() { + return Stream.of( + Arguments.of('T', 'F', true, 'T'), + Arguments.of('T', 'F', false, 'F') + ); + } + + + @ParameterizedTest + @MethodSource("toCharacterCustomParams") + void testToCharacter_withCustomChars(char trueChar, char falseChar, boolean value, char expected) { + ConverterOptions options = createConvertOptions(trueChar, falseChar); + char actual = BooleanConversions.toCharacter(value, null, options); + assertThat(actual).isEqualTo(expected); + } + + + private static Stream toBigDecimalParams() { + return Stream.of( + Arguments.of(true, BigDecimal.ONE), + Arguments.of(false, BigDecimal.ZERO) + ); + } + + @ParameterizedTest + @MethodSource("toBigDecimalParams") + void testToBigDecimal(boolean value, BigDecimal expected) { + BigDecimal actual = AtomicBooleanConversions.toBigDecimal(new AtomicBoolean(value), null, null); + assertThat(actual).isSameAs(expected); + } + + private static Stream toBigIntegerParams() { + return Stream.of( + Arguments.of(true, BigInteger.ONE), + Arguments.of(false, BigInteger.ZERO) + ); + } + @ParameterizedTest + @MethodSource("toBigIntegerParams") + void testToBigDecimal(boolean value, BigInteger expected) { + BigInteger actual = AtomicBooleanConversions.toBigInteger(new AtomicBoolean(value), null, null); + assertThat(actual).isSameAs(expected); + } + + private ConverterOptions createConvertOptions(final char t, final char f) + { + return new ConverterOptions() { + @Override + public T getCustomOption(String name) { + return null; + } + + @Override + public Character trueChar() { return t; } + + @Override + public Character falseChar() { return f; } + }; + } +} + diff --git a/src/test/java/com/cedarsoftware/util/convert/BooleanConversionsTests.java b/src/test/java/com/cedarsoftware/util/convert/BooleanConversionsTests.java new file mode 100644 index 00000000..208b0c72 --- /dev/null +++ b/src/test/java/com/cedarsoftware/util/convert/BooleanConversionsTests.java @@ -0,0 +1,229 @@ +package com.cedarsoftware.util.convert; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; +import java.math.BigDecimal; +import java.math.BigInteger; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class BooleanConversionsTests { + + + @Test + public void testClassCompliance() throws Exception { + Class c = BooleanConversions.class; + assertEquals(Modifier.FINAL, c.getModifiers() & Modifier.FINAL); + + Constructor con = c.getDeclaredConstructor(); + assertEquals(Modifier.PRIVATE, con.getModifiers() & Modifier.PRIVATE); + + con.setAccessible(true); + assertNotNull(con.newInstance()); + } + + private static Stream toByteParams() { + return Stream.of( + Arguments.of(true, CommonValues.BYTE_ONE), + Arguments.of(false, CommonValues.BYTE_ZERO) + ); + } + + @ParameterizedTest + @MethodSource("toByteParams") + void testToByte(boolean value, Byte expected) { + Byte actual = BooleanConversions.toByte(value, null, null); + assertThat(actual).isSameAs(expected); + } + + private static Stream toShortParams() { + return Stream.of( + Arguments.of(true, CommonValues.SHORT_ONE), + Arguments.of(false, CommonValues.SHORT_ZERO) + ); + } + + @ParameterizedTest + @MethodSource("toShortParams") + void testToShort(boolean value, Short expected) { + Short actual = BooleanConversions.toShort(value, null, null); + assertThat(actual).isSameAs(expected); + } + + private static Stream toIntegerParams() { + return Stream.of( + Arguments.of(true, CommonValues.INTEGER_ONE), + Arguments.of(false, CommonValues.INTEGER_ZERO) + ); + } + + @ParameterizedTest + @MethodSource("toIntegerParams") + void testToInteger(boolean value, Integer expected) { + Integer actual = BooleanConversions.toInteger(value, null, null); + assertThat(actual).isSameAs(expected); + } + + private static Stream toLongParams() { + return Stream.of( + Arguments.of(true, CommonValues.LONG_ONE), + Arguments.of(false, CommonValues.LONG_ZERO) + ); + } + + @ParameterizedTest + @MethodSource("toLongParams") + void testToLong(boolean value, long expected) { + long actual = BooleanConversions.toLong(value, null, null); + assertThat(actual).isSameAs(expected); + } + + private static Stream toFloatParams() { + return Stream.of( + Arguments.of(true, CommonValues.FLOAT_ONE), + Arguments.of(false, CommonValues.FLOAT_ZERO) + ); + } + + @ParameterizedTest + @MethodSource("toFloatParams") + void testToFloat(boolean value, Float expected) { + Float actual = BooleanConversions.toFloat(value, null, null); + assertThat(actual).isSameAs(expected); + } + + + private static Stream toDoubleParams() { + return Stream.of( + Arguments.of(true, CommonValues.DOUBLE_ONE), + Arguments.of(false, CommonValues.DOUBLE_ZERO) + ); + } + + @ParameterizedTest + @MethodSource("toDoubleParams") + void testToDouble(boolean value, Double expected) { + Double actual = BooleanConversions.toDouble(value, null, null); + assertThat(actual).isSameAs(expected); + } + + + private static Stream toBooleanParams() { + return Stream.of( + Arguments.of(true), + Arguments.of(false) + ); + } + + @ParameterizedTest + @MethodSource("toBooleanParams") + void testToAtomicBoolean(boolean value) { + AtomicBoolean expected = new AtomicBoolean(value);; + AtomicBoolean actual = BooleanConversions.toAtomicBoolean(value, null, null); + assertThat(actual.get()).isEqualTo(expected.get()); + } + + @ParameterizedTest + @MethodSource("toIntegerParams") + void testToAtomicInteger(boolean value, int integer) { + AtomicInteger expected = new AtomicInteger(integer);; + AtomicInteger actual = BooleanConversions.toAtomicInteger(value, null, null); + assertThat(actual.get()).isEqualTo(expected.get()); + } + + @ParameterizedTest + @MethodSource("toLongParams") + void testToAtomicLong(boolean value, long expectedLong) { + AtomicLong expected = new AtomicLong(expectedLong); + AtomicLong actual = BooleanConversions.toAtomicLong(value, null, null); + assertThat(actual.get()).isEqualTo(expected.get()); + } + + private static Stream toCharacterDefaultParams() { + return Stream.of( + Arguments.of(true, CommonValues.CHARACTER_ONE), + Arguments.of(false, CommonValues.CHARACTER_ZERO) + ); + } + + + @ParameterizedTest + @MethodSource("toCharacterDefaultParams") + void testToCharacter_withDefaultChars(boolean value, char expected) { + ConverterOptions options = createConvertOptions(CommonValues.CHARACTER_ONE, CommonValues.CHARACTER_ZERO); + Character actual = BooleanConversions.toCharacter(value, null, options); + assertThat(actual).isSameAs(expected); + } + + private static Stream toCharacterCustomParams() { + return Stream.of( + Arguments.of('T', 'F', true, 'T'), + Arguments.of('T', 'F', false, 'F') + ); + } + + + @ParameterizedTest + @MethodSource("toCharacterCustomParams") + void testToCharacter_withCustomChars(char trueChar, char falseChar, boolean value, char expected) { + ConverterOptions options = createConvertOptions(trueChar, falseChar); + char actual = BooleanConversions.toCharacter(value, null, options); + assertThat(actual).isEqualTo(expected); + } + + private static Stream toBigDecimalParams() { + return Stream.of( + Arguments.of(true, BigDecimal.ONE), + Arguments.of(false, BigDecimal.ZERO) + ); + } + + @ParameterizedTest + @MethodSource("toBigDecimalParams") + void testToBigDecimal(boolean value, BigDecimal expected) { + BigDecimal actual = BooleanConversions.toBigDecimal(value, null, null); + assertThat(actual).isSameAs(expected); + } + + private static Stream toBigIntegerParams() { + return Stream.of( + Arguments.of(true, BigInteger.ONE), + Arguments.of(false, BigInteger.ZERO) + ); + } + @ParameterizedTest + @MethodSource("toBigIntegerParams") + void testToBigDecimal(boolean value, BigInteger expected) { + BigInteger actual = BooleanConversions.toBigInteger(value, null, null); + assertThat(actual).isSameAs(expected); + } + + private ConverterOptions createConvertOptions(final char t, final char f) + { + return new ConverterOptions() { + @Override + public T getCustomOption(String name) { + return null; + } + + @Override + public Character trueChar() { return t; } + + @Override + public Character falseChar() { return f; } + }; + } +} + diff --git a/src/test/java/com/cedarsoftware/util/convert/ConverterTest.java b/src/test/java/com/cedarsoftware/util/convert/ConverterTest.java index d7767f0f..0b305885 100644 --- a/src/test/java/com/cedarsoftware/util/convert/ConverterTest.java +++ b/src/test/java/com/cedarsoftware/util/convert/ConverterTest.java @@ -6,6 +6,7 @@ import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Calendar; @@ -22,7 +23,6 @@ import java.util.stream.Stream; import com.cedarsoftware.util.DeepEquals; -import com.cedarsoftware.util.TestUtil; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -32,8 +32,6 @@ import org.junit.jupiter.params.provider.NullAndEmptySource; import org.junit.jupiter.params.provider.NullSource; -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; @@ -66,8 +64,26 @@ class ConverterTest { + private static final LocalDateTime LDT_2023_TOKYO = LocalDateTime.of(2023, 6, 25, 0, 57, 29, 729000000); + private static final LocalDateTime LDT_2023_PARIS = LocalDateTime.of(2023, 6, 24, 17, 57, 29, 729000000); + private static final LocalDateTime LDT_2023_GMT = LocalDateTime.of(2023, 6, 24, 15, 57, 29, 729000000); + private static final LocalDateTime LDT_2023_NY = LocalDateTime.of(2023, 6, 24, 11, 57, 29, 729000000); + private static final LocalDateTime LDT_2023_CHICAGO = LocalDateTime.of(2023, 6, 24, 10, 57, 29, 729000000); + private static final LocalDateTime LDT_2023_LA = LocalDateTime.of(2023, 6, 24, 8, 57, 29, 729000000); + private static final LocalDateTime LDT_MILLENNIUM_TOKYO = LocalDateTime.of(2000, 1, 1, 13, 59, 59, 959000000); + private static final LocalDateTime LDT_MILLENNIUM_PARIS = LocalDateTime.of(2000, 1, 1, 5, 59, 59, 959000000); + private static final LocalDateTime LDT_MILLENNIUM_GMT = LocalDateTime.of(2000, 1, 1, 4, 59, 59, 959000000); + private static final LocalDateTime LDT_MILLENNIUM_NY = LocalDateTime.of(1999, 12, 31, 23, 59, 59, 959000000); + private static final LocalDateTime LDT_MILLENNIUM_CHICAGO = LocalDateTime.of(1999, 12, 31, 22, 59, 59, 959000000); + private static final LocalDateTime LDT_MILLENNIUM_LA = LocalDateTime.of(1999, 12, 31, 20, 59, 59, 959000000); private Converter converter; + + private static final LocalDate LD_MILLINNIUM_NY = LocalDate.of(1999, 12, 31); + private static final LocalDate LD_MILLINNIUM_TOKYO = LocalDate.of(2000, 1, 1); + + private static final LocalDate LD_MILLENNIUM_CHICAGO = LocalDate.of(1999, 12, 31); + enum fubar { foo, bar, baz, quz @@ -700,18 +716,18 @@ void testToBoolean_falseCases(Object input) { 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)) + Arguments.of(1687622249729L, TOKYO, LDT_2023_TOKYO), + Arguments.of(1687622249729L, PARIS, LDT_2023_PARIS), + Arguments.of(1687622249729L, GMT, LDT_2023_GMT), + Arguments.of(1687622249729L, NEW_YORK, LDT_2023_NY), + Arguments.of(1687622249729L, CHICAGO, LDT_2023_CHICAGO), + Arguments.of(1687622249729L, LOS_ANGELES, LDT_2023_LA), + Arguments.of(946702799959L, TOKYO, LDT_MILLENNIUM_TOKYO), + Arguments.of(946702799959L, PARIS, LDT_MILLENNIUM_PARIS), + Arguments.of(946702799959L, GMT, LDT_MILLENNIUM_GMT), + Arguments.of(946702799959L, NEW_YORK, LDT_MILLENNIUM_NY), + Arguments.of(946702799959L, CHICAGO, LDT_MILLENNIUM_CHICAGO), + Arguments.of(946702799959L, LOS_ANGELES, LDT_MILLENNIUM_LA) ); } @@ -727,6 +743,7 @@ void testCalendarToLocalDateTime(long epochMilli, ZoneId zoneId, LocalDateTime e assertThat(localDateTime).isEqualTo(expected); } + @ParameterizedTest @MethodSource("epochMillis_withLocalDateTimeInformation") void testCalendarToLocalDateTime_whenCalendarTimeZoneMatches(long epochMilli, ZoneId zoneId, LocalDateTime expected) { @@ -734,66 +751,269 @@ void testCalendarToLocalDateTime_whenCalendarTimeZoneMatches(long epochMilli, Zo calendar.setTimeInMillis(epochMilli); LocalDateTime localDateTime = this.converter.convert(calendar, LocalDateTime.class, createConvertOptions(zoneId, zoneId)); + assertThat(localDateTime).isEqualTo(expected); } - @Test - void testCalendarToLocalDateTime_whenCalendarTimeZoneDoesNotMatch() { + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testCalendarToLocalDateTime_whenCalendarTimeZoneDoesNotMatch(long epochMilli, ZoneId zoneId, LocalDateTime expected) { Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone(NEW_YORK)); - calendar.setTimeInMillis(1687622249729L); + calendar.setTimeInMillis(epochMilli); - LocalDateTime localDateTime = this.converter.convert(calendar, LocalDateTime.class, createConvertOptions(NEW_YORK, TOKYO)); + LocalDateTime localDateTime = this.converter.convert(calendar, LocalDateTime.class, createConvertOptions(NEW_YORK, zoneId)); - System.out.println(localDateTime); + assertThat(localDateTime).isEqualTo(expected); + } - assertThat(localDateTime) - .hasYear(2023) - .hasMonthValue(6) - .hasDayOfMonth(25) - .hasHour(0) - .hasMinute(57) - .hasSecond(29) - .hasNano(729000000); + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testCalendar_roundTrip(long epochMilli, ZoneId zoneId, LocalDateTime expected) { + Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone(zoneId)); + calendar.setTimeInMillis(epochMilli); + + assertThat(calendar.get(Calendar.YEAR)).isEqualTo(expected.getYear()); + assertThat(calendar.get(Calendar.MONTH)).isEqualTo(expected.getMonthValue()-1); + assertThat(calendar.get(Calendar.DAY_OF_MONTH)).isEqualTo(expected.getDayOfMonth()); + assertThat(calendar.get(Calendar.HOUR_OF_DAY)).isEqualTo(expected.getHour()); + assertThat(calendar.get(Calendar.MINUTE)).isEqualTo(expected.getMinute()); + assertThat(calendar.get(Calendar.SECOND)).isEqualTo(expected.getSecond()); + assertThat(calendar.getTimeInMillis()).isEqualTo(epochMilli); + + + LocalDateTime localDateTime = this.converter.convert(calendar, LocalDateTime.class, createConvertOptions(zoneId, TOKYO)); + + Calendar actual = this.converter.convert(localDateTime, Calendar.class, createConvertOptions(TOKYO, zoneId)); + + assertThat(actual.get(Calendar.YEAR)).isEqualTo(expected.getYear()); + assertThat(actual.get(Calendar.MONTH)).isEqualTo(expected.getMonthValue()-1); + assertThat(actual.get(Calendar.DAY_OF_MONTH)).isEqualTo(expected.getDayOfMonth()); + assertThat(actual.get(Calendar.HOUR_OF_DAY)).isEqualTo(expected.getHour()); + assertThat(actual.get(Calendar.MINUTE)).isEqualTo(expected.getMinute()); + assertThat(actual.get(Calendar.SECOND)).isEqualTo(expected.getSecond()); + assertThat(actual.getTimeInMillis()).isEqualTo(epochMilli); + } + + + private static Stream roundTrip_tokyoTime() { + return Stream.of( + Arguments.of(946652400000L, TOKYO, LD_MILLINNIUM_TOKYO), + Arguments.of(946652400000L, NEW_YORK, LD_MILLINNIUM_NY), + Arguments.of(946652400000L, CHICAGO, LD_MILLENNIUM_CHICAGO) + ); + } + + @ParameterizedTest + @MethodSource("roundTrip_tokyoTime") + void testCalendar_roundTrip_withLocalDate(long epochMilli, ZoneId zoneId, LocalDate expected) { + Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone(zoneId)); + calendar.setTimeInMillis(epochMilli); + + assertThat(calendar.get(Calendar.YEAR)).isEqualTo(expected.getYear()); + assertThat(calendar.get(Calendar.MONTH)).isEqualTo(expected.getMonthValue()-1); + assertThat(calendar.get(Calendar.DAY_OF_MONTH)).isEqualTo(expected.getDayOfMonth()); + assertThat(calendar.getTimeInMillis()).isEqualTo(epochMilli); + + + LocalDate localDate = this.converter.convert(calendar, LocalDate.class, createConvertOptions(zoneId, TOKYO)); + + Calendar actual = this.converter.convert(localDate, Calendar.class, createConvertOptions(TOKYO, zoneId)); + + assertThat(actual.get(Calendar.YEAR)).isEqualTo(expected.getYear()); + assertThat(actual.get(Calendar.MONTH)).isEqualTo(expected.getMonthValue()-1); + assertThat(actual.get(Calendar.DAY_OF_MONTH)).isEqualTo(expected.getDayOfMonth()); + + assertThat(actual.getTimeInMillis()).isEqualTo(epochMilli); + } + + private static Stream localDateToLong() { + return Stream.of( + Arguments.of(946616400000L, NEW_YORK, LD_MILLINNIUM_NY, TOKYO), + Arguments.of(946616400000L, NEW_YORK, LD_MILLINNIUM_NY, CHICAGO), + Arguments.of(946620000000L, CHICAGO, LD_MILLENNIUM_CHICAGO, TOKYO) + ); + } + @ParameterizedTest + @MethodSource("localDateToLong") + void testConvertLocalDateToLongAndBack(long epochMilli, ZoneId zoneId, LocalDate expected, ZoneId targetZone) { + + long intermediate = this.converter.convert(expected, long.class, createConvertOptions(zoneId, targetZone)); + + assertThat(intermediate).isEqualTo(epochMilli); + + LocalDate actual = this.converter.convert(intermediate, LocalDate.class, createConvertOptions(targetZone, zoneId)); + + assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("localDateToLong") + void testLocalDateToInstantAndBack(long epochMilli, ZoneId zoneId, LocalDate expected, ZoneId targetZone) { + + Instant intermediate = this.converter.convert(expected, Instant.class, createConvertOptions(zoneId, targetZone)); + + assertThat(intermediate.toEpochMilli()).isEqualTo(epochMilli); + + LocalDate actual = this.converter.convert(intermediate, LocalDate.class, createConvertOptions(targetZone, zoneId)); + + assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("localDateToLong") + void testLocalDateToDoubleAndBack(long epochMilli, ZoneId zoneId, LocalDate expected, ZoneId targetZone) { + + double intermediate = this.converter.convert(expected, double.class, createConvertOptions(zoneId, targetZone)); + + assertThat((long)intermediate).isEqualTo(epochMilli); + + LocalDate actual = this.converter.convert(intermediate, LocalDate.class, createConvertOptions(targetZone, zoneId)); + + assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("localDateToLong") + void testLocalDateToAtomicLongAndBack(long epochMilli, ZoneId zoneId, LocalDate expected, ZoneId targetZone) { + + AtomicLong intermediate = this.converter.convert(expected, AtomicLong.class, createConvertOptions(zoneId, targetZone)); + + assertThat(intermediate.get()).isEqualTo(epochMilli); + + LocalDate actual = this.converter.convert(intermediate, LocalDate.class, createConvertOptions(targetZone, zoneId)); + + assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("localDateToLong") + void testLocalDateToDateAndBack(long epochMilli, ZoneId zoneId, LocalDate expected, ZoneId targetZone) { + + Date intermediate = this.converter.convert(expected,Date.class, createConvertOptions(zoneId, targetZone)); + + assertThat(intermediate.getTime()).isEqualTo(epochMilli); + + LocalDate actual = this.converter.convert(intermediate, LocalDate.class, createConvertOptions(targetZone, zoneId)); + + assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("localDateToLong") + void testLocalDateSqlDateAndBack(long epochMilli, ZoneId zoneId, LocalDate expected, ZoneId targetZone) { + + java.sql.Date intermediate = this.converter.convert(expected, java.sql.Date.class, createConvertOptions(zoneId, targetZone)); + + assertThat(intermediate.getTime()).isEqualTo(epochMilli); + + LocalDate actual = this.converter.convert(intermediate, LocalDate.class, createConvertOptions(targetZone, zoneId)); + + assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("localDateToLong") + void testLocalDateTimestampAndBack(long epochMilli, ZoneId zoneId, LocalDate expected, ZoneId targetZone) { + + Timestamp intermediate = this.converter.convert(expected, Timestamp.class, createConvertOptions(zoneId, targetZone)); + + assertThat(intermediate.getTime()).isEqualTo(epochMilli); + + LocalDate actual = this.converter.convert(intermediate, LocalDate.class, createConvertOptions(targetZone, zoneId)); + + assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("localDateToLong") + void testLocalDateZonedDateTimeAndBack(long epochMilli, ZoneId zoneId, LocalDate expected, ZoneId targetZone) { + + ZonedDateTime intermediate = this.converter.convert(expected, ZonedDateTime.class, createConvertOptions(zoneId, targetZone)); + + assertThat(intermediate.toInstant().toEpochMilli()).isEqualTo(epochMilli); + + LocalDate actual = this.converter.convert(intermediate, LocalDate.class, createConvertOptions(targetZone, zoneId)); + + assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("localDateToLong") + void testLocalDateToLocalDateTimeAndBack(long epochMilli, ZoneId zoneId, LocalDate expected, ZoneId targetZone) { + + LocalDateTime intermediate = this.converter.convert(expected, LocalDateTime.class, createConvertOptions(zoneId, targetZone)); + + LocalDate actual = this.converter.convert(intermediate, LocalDate.class, createConvertOptions(targetZone, zoneId)); + + assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("localDateToLong") + void testLocalDateToBigIntegerAndBack(long epochMilli, ZoneId zoneId, LocalDate expected, ZoneId targetZone) { + + BigInteger intermediate = this.converter.convert(expected, BigInteger.class, createConvertOptions(zoneId, targetZone)); + + assertThat(intermediate.longValue()).isEqualTo(epochMilli); + + LocalDate actual = this.converter.convert(intermediate, LocalDate.class, createConvertOptions(targetZone, zoneId)); + + assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("localDateToLong") + void testLocalDateToBigDecimalAndBack(long epochMilli, ZoneId zoneId, LocalDate expected, ZoneId targetZone) { + + BigDecimal intermediate = this.converter.convert(expected, BigDecimal.class, createConvertOptions(zoneId, targetZone)); + + assertThat(intermediate.longValue()).isEqualTo(epochMilli); + + LocalDate actual = this.converter.convert(intermediate, LocalDate.class, createConvertOptions(targetZone, zoneId)); + + assertThat(actual).isEqualTo(expected); } @Test - void testCalendar_roundTrip() { + void testLocalDateToFloat() { - // Create LocalDateTime as CHICAGO TIME. - GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone(CHICAGO)); - calendar.setTimeInMillis(1687622249729L); + float intermediate = this.converter.convert(LD_MILLINNIUM_NY, float.class, createConvertOptions(NEW_YORK, TOKYO)); - 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); + assertThat((long)intermediate).isNotEqualTo(946616400000L); + } - // Convert calendar calendar to TOKYO LocalDateTime - LocalDateTime localDateTime = this.converter.convert(calendar, LocalDateTime.class, createConvertOptions(CHICAGO, TOKYO)); + @Test + void testLocalDateToLocalTime_withZoneChange_willBeZoneOffset() { - assertThat(localDateTime) - .hasYear(2023) - .hasMonthValue(6) - .hasDayOfMonth(25) - .hasHour(0) - .hasMinute(57) - .hasSecond(29) - .hasNano(729000000); + LocalTime intermediate = this.converter.convert(LD_MILLINNIUM_NY, LocalTime.class, createConvertOptions(NEW_YORK, TOKYO)); - // 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(intermediate).hasHour(14) + .hasMinute(0) + .hasSecond(0) + .hasNano(0); + } - 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 testLocalDateToLocalTimeWithoutZoneChange_willBeMidnight() { + + LocalTime intermediate = this.converter.convert(LD_MILLINNIUM_NY, LocalTime.class, createConvertOptions(NEW_YORK, NEW_YORK)); + + assertThat(intermediate).hasHour(0) + .hasMinute(0) + .hasSecond(0) + .hasNano(0); } + @ParameterizedTest + @MethodSource("localDateToLong") + void testLocalDateToLocalTime(long epochMilli, ZoneId zoneId, LocalDate expected, ZoneId targetZone) { + + float intermediate = this.converter.convert(expected, float.class, createConvertOptions(zoneId, targetZone)); + + assertThat((long)intermediate).isNotEqualTo(epochMilli); + } + + @ParameterizedTest @MethodSource("epochMillis_withLocalDateTimeInformation") void testZonedDateTimeToLocalDateTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) @@ -807,6 +1027,52 @@ void testZonedDateTimeToLocalDateTime(long epochMilli, ZoneId zoneId, LocalDateT } + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testZonedDateTimeToLocalTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + ZonedDateTime time = Instant.ofEpochMilli(epochMilli).atZone(zoneId); + + LocalTime actual = this.converter.convert(time, LocalTime.class, createConvertOptions(zoneId, zoneId)); + + assertThat(actual).isEqualTo(expected.toLocalTime()); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testZonedDateTimeToLocalDate(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + ZonedDateTime time = Instant.ofEpochMilli(epochMilli).atZone(zoneId); + + LocalDate actual = this.converter.convert(time, LocalDate.class, createConvertOptions(zoneId, zoneId)); + + assertThat(actual).isEqualTo(expected.toLocalDate()); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testZonedDateTimeToInstant(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + ZonedDateTime time = Instant.ofEpochMilli(epochMilli).atZone(zoneId); + + Instant actual = this.converter.convert(time, Instant.class, createConvertOptions(zoneId, zoneId)); + + assertThat(actual).isEqualTo(time.toInstant()); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testZonedDateTimeToCalendar(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + ZonedDateTime time = Instant.ofEpochMilli(epochMilli).atZone(zoneId); + + Calendar actual = this.converter.convert(time, Calendar.class, createConvertOptions(zoneId, zoneId)); + + assertThat(actual.getTime().getTime()).isEqualTo(time.toInstant().toEpochMilli()); + assertThat(actual.getTimeZone()).isEqualTo(TimeZone.getTimeZone(zoneId)); + } + + @ParameterizedTest @MethodSource("epochMillis_withLocalDateTimeInformation") void testZonedDateTimeToLong(long epochMilli, ZoneId zoneId, LocalDateTime localDateTime) @@ -875,6 +1141,33 @@ void testDateToLocalDateTime(long epochMilli, ZoneId zoneId, LocalDateTime expec assertThat(localDateTime).isEqualTo(expected); } + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testDateToZonedDateTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Date date = new Date(epochMilli); + ZonedDateTime zonedDateTime = this.converter.convert(date, ZonedDateTime.class, createConvertOptions(null, zoneId)); + assertThat(zonedDateTime.toLocalDateTime()).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testInstantToZonedDateTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Instant date = Instant.ofEpochMilli(epochMilli); + ZonedDateTime zonedDateTime = this.converter.convert(date, ZonedDateTime.class, createConvertOptions(null, zoneId)); + assertThat(zonedDateTime.toInstant()).isEqualTo(date); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testDateToInstant(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Date date = new Date(epochMilli); + Instant actual = this.converter.convert(date, Instant.class, createConvertOptions(null, zoneId)); + assertThat(actual.toEpochMilli()).isEqualTo(epochMilli); + } + @ParameterizedTest @MethodSource("epochMillis_withLocalDateTimeInformation") @@ -885,6 +1178,117 @@ void testSqlDateToLocalDateTime(long epochMilli, ZoneId zoneId, LocalDateTime ex assertThat(localDateTime).isEqualTo(expected); } + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testInstantToLong(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Instant instant = Instant.ofEpochMilli(epochMilli); + long actual = this.converter.convert(instant, long.class, createConvertOptions(null, zoneId)); + assertThat(actual).isEqualTo(epochMilli); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testInstantToAtomicLong(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Instant instant = Instant.ofEpochMilli(epochMilli); + AtomicLong actual = this.converter.convert(instant, AtomicLong.class, createConvertOptions(null, zoneId)); + assertThat(actual.get()).isEqualTo(epochMilli); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testInstantToFloat(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Instant instant = Instant.ofEpochMilli(epochMilli); + float actual = this.converter.convert(instant, float.class, createConvertOptions(null, zoneId)); + assertThat(actual).isEqualTo((float)epochMilli); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testInstantToDouble(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Instant instant = Instant.ofEpochMilli(epochMilli); + double actual = this.converter.convert(instant, double.class, createConvertOptions(null, zoneId)); + assertThat(actual).isEqualTo((double)epochMilli); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testInstantToTimestamp(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Instant instant = Instant.ofEpochMilli(epochMilli); + Timestamp actual = this.converter.convert(instant, Timestamp.class, createConvertOptions(null, zoneId)); + assertThat(actual.getTime()).isEqualTo(epochMilli); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testInstantToDate(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Instant instant = Instant.ofEpochMilli(epochMilli); + Date actual = this.converter.convert(instant, Date.class, createConvertOptions(null, zoneId)); + assertThat(actual.getTime()).isEqualTo(epochMilli); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testInstantToSqlDate(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Instant instant = Instant.ofEpochMilli(epochMilli); + java.sql.Date actual = this.converter.convert(instant, java.sql.Date.class, createConvertOptions(null, zoneId)); + assertThat(actual.getTime()).isEqualTo(epochMilli); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testInstantToCalendar(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Instant instant = Instant.ofEpochMilli(epochMilli); + Calendar actual = this.converter.convert(instant, Calendar.class, createConvertOptions(null, zoneId)); + assertThat(actual.getTime().getTime()).isEqualTo(epochMilli); + assertThat(actual.getTimeZone()).isEqualTo(TimeZone.getTimeZone(zoneId)); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testInstantToBigInteger(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Instant instant = Instant.ofEpochMilli(epochMilli); + BigInteger actual = this.converter.convert(instant, BigInteger.class, createConvertOptions(null, zoneId)); + assertThat(actual.longValue()).isEqualTo(epochMilli); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testInstantToBigDecimal(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Instant instant = Instant.ofEpochMilli(epochMilli); + BigDecimal actual = this.converter.convert(instant, BigDecimal.class, createConvertOptions(null, zoneId)); + assertThat(actual.longValue()).isEqualTo(epochMilli); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testInstantToLocalDate(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Instant instant = Instant.ofEpochMilli(epochMilli); + LocalDate actual = this.converter.convert(instant, LocalDate.class, createConvertOptions(null, zoneId)); + assertThat(actual).isEqualTo(expected.toLocalDate()); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testInstantToLocalTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) + { + Instant instant = Instant.ofEpochMilli(epochMilli); + LocalTime actual = this.converter.convert(instant, LocalTime.class, createConvertOptions(null, zoneId)); + assertThat(actual).isEqualTo(expected.toLocalTime()); + } + + + @ParameterizedTest @MethodSource("epochMillis_withLocalDateTimeInformation") void testTimestampToLocalDateTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) @@ -914,6 +1318,16 @@ private static Stream epochMillis_withLocalDateInformation() { } + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateInformation") + void testCalendarToDouble(long epochMilli, ZoneId zoneId, LocalDate expected) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(epochMilli); + + double d = this.converter.convert(calendar, double.class, createConvertOptions(null, zoneId)); + assertThat(d).isEqualTo((double)epochMilli); + } + @ParameterizedTest @MethodSource("epochMillis_withLocalDateInformation") void testCalendarToLocalDate(long epochMilli, ZoneId zoneId, LocalDate expected) { @@ -924,6 +1338,45 @@ void testCalendarToLocalDate(long epochMilli, ZoneId zoneId, LocalDate expected) assertThat(localDate).isEqualTo(expected); } + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testCalendarToLocalTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(epochMilli); + + LocalTime actual = this.converter.convert(calendar, LocalTime.class, createConvertOptions(null, zoneId)); + assertThat(actual).isEqualTo(expected.toLocalTime()); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testCalendarToZonedDateTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(epochMilli); + + ZonedDateTime actual = this.converter.convert(calendar, ZonedDateTime.class, createConvertOptions(null, zoneId)); + assertThat(actual.toLocalDateTime()).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testCalendarToInstant(long epochMilli, ZoneId zoneId, LocalDateTime expected) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(epochMilli); + + Instant actual = this.converter.convert(calendar, Instant.class, createConvertOptions(null, zoneId)); + assertThat(actual.toEpochMilli()).isEqualTo(epochMilli); + } + + @ParameterizedTest + @MethodSource("epochMillis_withLocalDateTimeInformation") + void testDateToLocalTime(long epochMilli, ZoneId zoneId, LocalDateTime expected) { + Date date = new Date(epochMilli); + + LocalTime actual = this.converter.convert(date, LocalTime.class, createConvertOptions(null, zoneId)); + assertThat(actual).isEqualTo(expected.toLocalTime()); + } + @ParameterizedTest @MethodSource("epochMillis_withLocalDateInformation") void testCalendarToLocalDate_whenCalendarTimeZoneMatches(long epochMilli, ZoneId zoneId, LocalDate expected) { @@ -948,7 +1401,7 @@ void testCalendarToLocalDate_whenCalendarTimeZoneDoesNotMatchTarget_convertsTime } @Test - void testCalendar_testData() { + void testCalendar_testRoundTripWithLocalDate() { // Create LocalDateTime as CHICAGO TIME. GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone(CHICAGO)); @@ -1058,15 +1511,22 @@ void testTimestampToLocalDate(long epochMilli, ZoneId zoneId, LocalDate 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); + @ParameterizedTest + @MethodSource("localDateTimeConversion_params") + void testLocalDateToLong(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); + } + 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) + Arguments.of(1687622249729L, NEW_YORK, LDT_2023_NY, TOKYO, LDT_2023_TOKYO), + Arguments.of(1687622249729L, LOS_ANGELES, LDT_2023_LA, PARIS, LDT_2023_PARIS) ); } @@ -1078,7 +1538,18 @@ void testLocalDateTimeToLong(long epochMilli, ZoneId sourceZoneId, LocalDateTime 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)); + LocalDateTime actual = this.converter.convert(milli, LocalDateTime.class, createConvertOptions(null, targetZoneId)); + assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("localDateTimeConversion_params") + void testLocalDateTimeToInstant(long epochMilli, ZoneId sourceZoneId, LocalDateTime initial, ZoneId targetZoneId, LocalDateTime expected) + { + Instant intermediate = this.converter.convert(initial, Instant.class, createConvertOptions(sourceZoneId, targetZoneId)); + assertThat(intermediate.toEpochMilli()).isEqualTo(epochMilli); + + LocalDateTime actual = this.converter.convert(intermediate, LocalDateTime.class, createConvertOptions(null, targetZoneId)); assertThat(actual).isEqualTo(expected); } @@ -1089,10 +1560,30 @@ void testLocalDateTimeToAtomicLong(long epochMilli, ZoneId sourceZoneId, LocalDa 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)); + LocalDateTime actual = this.converter.convert(milli, LocalDateTime.class, createConvertOptions(null, targetZoneId)); + assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("localDateTimeConversion_params") + void testLocalDateTimeToZonedDateTime(long epochMilli, ZoneId sourceZoneId, LocalDateTime initial, ZoneId targetZoneId, LocalDateTime expected) + { + ZonedDateTime intermediate = this.converter.convert(initial, ZonedDateTime.class, createConvertOptions(sourceZoneId, targetZoneId)); + assertThat(intermediate.toInstant().toEpochMilli()).isEqualTo(epochMilli); + + LocalDateTime actual = this.converter.convert(intermediate, LocalDateTime.class, createConvertOptions(null, targetZoneId)); assertThat(actual).isEqualTo(expected); } + @ParameterizedTest + @MethodSource("localDateTimeConversion_params") + void testLocalDateTimeToLocalTime(long epochMilli, ZoneId sourceZoneId, LocalDateTime initial, ZoneId targetZoneId, LocalDateTime expected) + { + LocalTime intermediate = this.converter.convert(initial, LocalTime.class, createConvertOptions(sourceZoneId, targetZoneId)); + + assertThat(intermediate).isEqualTo(expected.toLocalTime()); + } + @ParameterizedTest @MethodSource("localDateTimeConversion_params") void testLocalDateTimeToBigInteger(long epochMilli, ZoneId sourceZoneId, LocalDateTime initial, ZoneId targetZoneId, LocalDateTime expected) @@ -1100,7 +1591,7 @@ void testLocalDateTimeToBigInteger(long epochMilli, ZoneId sourceZoneId, LocalDa 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)); + LocalDateTime actual = this.converter.convert(milli, LocalDateTime.class, createConvertOptions(null, targetZoneId)); assertThat(actual).isEqualTo(expected); } @@ -1112,7 +1603,7 @@ void testLocalDateTimeToBigDecimal(long epochMilli, ZoneId sourceZoneId, LocalDa 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)); + LocalDateTime actual = this.converter.convert(milli, LocalDateTime.class, createConvertOptions(null, targetZoneId)); assertThat(actual).isEqualTo(expected); } @@ -1786,84 +2277,65 @@ void testBogusSqlDate2() .hasMessageContaining("Unsupported conversion, source type [Boolean (true)] target type 'java.sql.Date'"); } - @Test - void testCalendar() - { - // Date to Calendar - Date now = new Date(); - Calendar calendar = this.converter.convert(new Date(), Calendar.class); - assertEquals(calendar.getTime(), now); - - // SqlDate to Calendar - java.sql.Date sqlDate = this.converter.convert(now, java.sql.Date.class); - calendar = this.converter.convert(sqlDate, Calendar.class); - assertEquals(calendar.getTime(), sqlDate); - - // Timestamp to Calendar - Timestamp timestamp = this.converter.convert(now, Timestamp.class); - calendar = this.converter.convert(timestamp, Calendar.class); - assertEquals(calendar.getTime(), timestamp); - - // Long to Calendar - calendar = this.converter.convert(now.getTime(), Calendar.class); - assertEquals(calendar.getTime(), now); - - // AtomicLong to Calendar - AtomicLong atomicLong = new AtomicLong(now.getTime()); - calendar = this.converter.convert(atomicLong, Calendar.class); - assertEquals(calendar.getTime(), now); - - // String to Calendar - String strDate = this.converter.convert(now, String.class); - calendar = this.converter.convert(strDate, Calendar.class); - String strDate2 = this.converter.convert(calendar, String.class); - assertEquals(strDate, strDate2); - - // BigInteger to Calendar - BigInteger bigInt = new BigInteger("" + now.getTime()); - calendar = this.converter.convert(bigInt, Calendar.class); - assertEquals(calendar.getTime(), now); - - // BigDecimal to Calendar - BigDecimal bigDec = new BigDecimal(now.getTime()); - calendar = this.converter.convert(bigDec, Calendar.class); - assertEquals(calendar.getTime(), now); - - // Other direction --> Calendar to other date types - - // Calendar to Date - calendar = this.converter.convert(now, Calendar.class); - Date date = this.converter.convert(calendar, Date.class); - assertEquals(calendar.getTime(), date); - - // Calendar to SqlDate - sqlDate = this.converter.convert(calendar, java.sql.Date.class); - assertEquals(calendar.getTime().getTime(), sqlDate.getTime()); - - // Calendar to Timestamp - timestamp = this.converter.convert(calendar, Timestamp.class); - assertEquals(calendar.getTime().getTime(), timestamp.getTime()); - - // Calendar to Long - long tnow = this.converter.convert(calendar, long.class); - assertEquals(calendar.getTime().getTime(), tnow); - - // Calendar to AtomicLong - atomicLong = this.converter.convert(calendar, AtomicLong.class); - assertEquals(calendar.getTime().getTime(), atomicLong.get()); + private static Stream toCalendarParams() { + return Stream.of( + Arguments.of(new Date(1687622249729L)), + Arguments.of(new java.sql.Date(1687622249729L)), + Arguments.of(new Timestamp(1687622249729L)), + Arguments.of(Instant.ofEpochMilli(1687622249729L)), + Arguments.of(1687622249729L), + Arguments.of(BigInteger.valueOf(1687622249729L)), + Arguments.of(BigDecimal.valueOf(1687622249729L)), + Arguments.of("1687622249729"), + Arguments.of(new AtomicLong(1687622249729L)) + ); + } - // Calendar to String - strDate = this.converter.convert(calendar, String.class); - strDate2 = this.converter.convert(now, String.class); - assertEquals(strDate, strDate2); + @ParameterizedTest + @MethodSource("toCalendarParams") + void toCalendar(Object source) + { + Long epochMilli = 1687622249729L; - // Calendar to BigInteger - bigInt = this.converter.convert(calendar, BigInteger.class); - assertEquals(now.getTime(), bigInt.longValue()); + Calendar calendar = this.converter.convert(source, Calendar.class); + assertEquals(calendar.getTime().getTime(), epochMilli); - // Calendar to BigDecimal - bigDec = this.converter.convert(calendar, BigDecimal.class); - assertEquals(now.getTime(), bigDec.longValue()); +// // BigInteger to Calendar +// // Other direction --> Calendar to other date types +// +// // Calendar to Date +// calendar = this.converter.convert(now, Calendar.class); +// Date date = this.converter.convert(calendar, Date.class); +// assertEquals(calendar.getTime(), date); +// +// // Calendar to SqlDate +// sqlDate = this.converter.convert(calendar, java.sql.Date.class); +// assertEquals(calendar.getTime().getTime(), sqlDate.getTime()); +// +// // Calendar to Timestamp +// timestamp = this.converter.convert(calendar, Timestamp.class); +// assertEquals(calendar.getTime().getTime(), timestamp.getTime()); +// +// // Calendar to Long +// long tnow = this.converter.convert(calendar, long.class); +// assertEquals(calendar.getTime().getTime(), tnow); +// +// // Calendar to AtomicLong +// atomicLong = this.converter.convert(calendar, AtomicLong.class); +// assertEquals(calendar.getTime().getTime(), atomicLong.get()); +// +// // Calendar to String +// strDate = this.converter.convert(calendar, String.class); +// strDate2 = this.converter.convert(now, String.class); +// assertEquals(strDate, strDate2); +// +// // Calendar to BigInteger +// bigInt = this.converter.convert(calendar, BigInteger.class); +// assertEquals(now.getTime(), bigInt.longValue()); +// +// // Calendar to BigDecimal +// bigDec = this.converter.convert(calendar, BigDecimal.class); +// assertEquals(now.getTime(), bigDec.longValue()); } @@ -1984,66 +2456,12 @@ void testConversions_whenClassTypeMatchesObjectType_stillCreatesNewObject(Object } @Test - void testLocalDateTimeToOthers() - { - // 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; + void testConvertStringToLocalDateTime_withParseError() { + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> this.converter.convert("2020-12-40", LocalDateTime.class)) + .withMessageContaining("Day must be between 1 and 31"); } - - @Test void testDateErrorHandlingBadInput() { @@ -2337,7 +2755,7 @@ void testMapToAtomicBoolean() map.clear(); assertThatThrownBy(() -> this.converter.convert(map, AtomicBoolean.class)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("the map must include keys: '_v' or 'value'"); + .hasMessageContaining("To convert from Map to AtomicBoolean the map must include one of the following"); } @Test @@ -2360,21 +2778,21 @@ void testMapToAtomicInteger() map.clear(); assertThatThrownBy(() -> this.converter.convert(map, AtomicInteger.class)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("the map must include keys: '_v' or 'value'"); + .hasMessageContaining("To convert from Map to AtomicInteger the map must include one of the following"); } @Test void testMapToAtomicLong() { final Map map = new HashMap(); - map.put("value", 58); - AtomicLong al = this.converter.convert(map, AtomicLong.class); - assert 58 == al.get(); - - map.clear(); - map.put("value", ""); - al = this.converter.convert(map, AtomicLong.class); - assert 0L == al.longValue(); +// map.put("value", 58); +// AtomicLong al = this.converter.convert(map, AtomicLong.class); +// assert 58 == al.get(); +// +// map.clear(); +// map.put("value", ""); +// al = this.converter.convert(map, AtomicLong.class); +// assert 0L == al.longValue(); map.clear(); map.put("value", null); @@ -2383,17 +2801,21 @@ void testMapToAtomicLong() map.clear(); assertThatThrownBy(() -> this.converter.convert(map, AtomicLong.class)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("the map must include keys: '_v' or 'value'"); + .hasMessageContaining("To convert from Map to AtomicLong the map must include one of the following"); } - @Test - void testMapToCalendar() + + + + @ParameterizedTest + @MethodSource("toCalendarParams") + void testMapToCalendar(Object value) { - long now = System.currentTimeMillis(); final Map map = new HashMap(); - map.put("value", new Date(now)); + map.put("value", value); + Calendar cal = this.converter.convert(map, Calendar.class); - assert now == cal.getTimeInMillis(); + assertThat(cal).isNotNull(); map.clear(); map.put("value", ""); @@ -2487,7 +2909,7 @@ void testMapToDate() { map.clear(); assertThatThrownBy(() -> this.converter.convert(map, Date.class)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("the map must include keys: [time], or '_v' or 'value'"); + .hasMessageContaining("To convert from Map to Date the map must include one of the following"); } @Test @@ -2510,7 +2932,7 @@ void testMapToSqlDate() map.clear(); assertThatThrownBy(() -> this.converter.convert(map, java.sql.Date.class)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("map must include keys"); + .hasMessageContaining("To convert from Map to java.sql.Date the map must include"); } @Test @@ -2533,7 +2955,7 @@ void testMapToTimestamp() map.clear(); assertThatThrownBy(() -> this.converter.convert(map, Timestamp.class)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("the map must include keys: [time, nanos], or '_v' or 'value'"); + .hasMessageContaining("To convert from Map to Timestamp the map must include one of the following"); } @Test @@ -2556,7 +2978,7 @@ void testMapToLocalDate() map.clear(); assertThatThrownBy(() -> this.converter.convert(map, LocalDate.class)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("Map to LocalDate, the map must include keys: [year, month, day], or '_v' or 'value'"); + .hasMessageContaining("To convert from Map to LocalDate, the map must include"); } @Test @@ -2579,7 +3001,7 @@ void testMapToLocalDateTime() map.clear(); assertThatThrownBy(() -> this.converter.convert(map, LocalDateTime.class)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("Map to LocalDateTime, the map must include keys: '_v' or 'value'"); + .hasMessageContaining("To convert from Map to LocalDateTime, the map must include"); } @Test @@ -2598,7 +3020,7 @@ void testMapToZonedDateTime() map.clear(); assertThatThrownBy(() -> this.converter.convert(map, ZonedDateTime.class)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("Map to ZonedDateTime, the map must include keys: '_v' or 'value'"); + .hasMessageContaining("To convert from Map to ZonedDateTime, the map must include"); } @@ -2968,7 +3390,7 @@ void testBadMapToUUID() map.put("leastSigBits", uuid.getLeastSignificantBits()); assertThatThrownBy(() -> this.converter.convert(map, UUID.class)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("To convert Map to UUID, the Map must contain both 'mostSigBits' and 'leastSigBits' keys"); + .hasMessageContaining("To convert from Map to UUID the map must include one of the following"); } @Test @@ -3298,8 +3720,6 @@ void testIsConversionSupport() { assert this.converter.isConversionSupportedFor(int.class, LocalDate.class); assert this.converter.isConversionSupportedFor(Integer.class, LocalDate.class); - assert this.converter.isConversionSupportedFor(LocalDate.class, int.class); - assert this.converter.isConversionSupportedFor(LocalDate.class, Integer.class); assert !this.converter.isDirectConversionSupportedFor(byte.class, LocalDate.class); assert this.converter.isConversionSupportedFor(byte.class, LocalDate.class); // byte is upgraded to Byte, which is found as Number. @@ -3668,5 +4088,5 @@ public ZoneId getSourceZoneIdForLocalDates() { }; } - private ConverterOptions chicagoZone() { return createConvertOptions(null, CHICAGO); } + private ConverterOptions chicagoZone() { return createConvertOptions(CHICAGO, CHICAGO); } }