diff --git a/api/src/org/labkey/api/data/ConvertHelper.java b/api/src/org/labkey/api/data/ConvertHelper.java index c65950942a8..fa5599ffc67 100644 --- a/api/src/org/labkey/api/data/ConvertHelper.java +++ b/api/src/org/labkey/api/data/ConvertHelper.java @@ -88,6 +88,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.Callable; /** @@ -1266,6 +1267,72 @@ public void testTrim() assertEquals(" x ", ConvertUtils.convert(" x ")); assertEquals(" x ", ConvertUtils.convert(" x ", String.class)); } + + Exception ex(Callable c) + { + try + { + c.call(); + return null; + } + catch (Exception x) + { + return x; + } + } + + @Test + public void testNumber() + { + // fractions -> integer + assertTrue(ex(()->JdbcType.BIGINT.convert("5.0001")) instanceof ConversionException); + assertTrue(ex(()->JdbcType.BIGINT.convert(new BigDecimal("5.0001"))) instanceof ConversionException); + assertTrue(ex(()->JdbcType.BIGINT.convert(5.0001f)) instanceof ConversionException); + assertTrue(ex(()->JdbcType.BIGINT.convert(5.0001d)) instanceof ConversionException); + assertTrue(ex(()->JdbcType.BIGINT.convert(5.0001d)).getMessage().startsWith("Could not convert '")); + + assertTrue(ex(()->JdbcType.INTEGER.convert("5.0001")) instanceof ConversionException); + assertTrue(ex(()->JdbcType.INTEGER.convert(new BigDecimal("5.0001"))) instanceof ConversionException); + assertTrue(ex(()->JdbcType.INTEGER.convert(5.0001f)) instanceof ConversionException); + assertTrue(ex(()->JdbcType.INTEGER.convert(5.0001d)) instanceof ConversionException); + + assertTrue(ex(()->JdbcType.SMALLINT.convert("5.0001")) instanceof ConversionException); + assertTrue(ex(()->JdbcType.SMALLINT.convert(new BigDecimal("5.0001"))) instanceof ConversionException); + assertTrue(ex(()->JdbcType.SMALLINT.convert(5.0001f)) instanceof ConversionException); + assertTrue(ex(()->JdbcType.SMALLINT.convert(5.0001d)) instanceof ConversionException); + + assertTrue(ex(()->PropertyType.BIGINT.convert("5.0001")) instanceof ConversionException); + assertTrue(ex(()->PropertyType.BIGINT.convert(new BigDecimal("5.0001"))) instanceof ConversionException); + assertTrue(ex(()->PropertyType.BIGINT.convert(5.0001f)) instanceof ConversionException); + assertTrue(ex(()->PropertyType.BIGINT.convert(5.0001d)) instanceof ConversionException); + assertTrue(ex(()->PropertyType.BIGINT.convert(5.0001d)).getMessage().startsWith("Could not convert '")); + + assertTrue(ex(()->PropertyType.INTEGER.convert("5.0001")) instanceof ConversionException); + assertTrue(ex(()->PropertyType.INTEGER.convert(new BigDecimal("5.0001"))) instanceof ConversionException); + assertTrue(ex(()->PropertyType.INTEGER.convert(5.0001f)) instanceof ConversionException); + assertTrue(ex(()->PropertyType.INTEGER.convert(5.0001d)) instanceof ConversionException); + + assertTrue(ex(()->ConvertUtils.convert("5.0001", Long.class)) instanceof ConversionException); + assertTrue(ex(()->ConvertUtils.convert(new BigDecimal("5.0001"), Long.class)) instanceof ConversionException); + assertTrue(ex(()->ConvertUtils.convert(5.0001f, Long.class)) instanceof ConversionException); + assertTrue(ex(()->ConvertUtils.convert(5.0001d, Long.class)) instanceof ConversionException); + assertTrue(ex(()->ConvertUtils.convert(5.0001d)).getMessage().startsWith("Could not convert '")); + + // OOR + assertTrue(ex(()->JdbcType.TINYINT.convert(Long.MAX_VALUE)) instanceof ConversionException); + assertTrue(ex(()->JdbcType.TINYINT.convert(10_000_000_000d)) instanceof ConversionException); + assertTrue(ex(()->JdbcType.TINYINT.convert("10000000000")) instanceof ConversionException); + assertTrue(ex(()->PropertyType.INTEGER.convert(Long.MAX_VALUE)) instanceof ConversionException); + assertTrue(ex(()->PropertyType.INTEGER.convert(10_000_000_000d)) instanceof ConversionException); + assertTrue(ex(()->PropertyType.INTEGER.convert("10000000000")) instanceof ConversionException); + assertTrue(ex(()->ConvertUtils.convert(10_000_000_000d, Short.class)) instanceof ConversionException); + assertTrue(ex(()->ConvertUtils.convert("10000000000", Short.class)) instanceof ConversionException); + assertEquals(Long.MAX_VALUE, ConvertUtils.convert(BigDecimal.valueOf(Long.MAX_VALUE), Long.class)); + assertEquals(Long.MIN_VALUE, ConvertUtils.convert(BigDecimal.valueOf(Long.MIN_VALUE), Long.class)); + // precision of Double is not high enough for this equality test to work for any random integer this large + assertEquals(Long.MAX_VALUE, ConvertUtils.convert(Double.valueOf(Long.MAX_VALUE), Long.class)); + assertEquals(Long.MIN_VALUE, ConvertUtils.convert(Double.valueOf(Long.MIN_VALUE), Long.class)); + } } // Note: Keep in sync with LabKeySiteWrapper.getConversionErrorMessage() diff --git a/api/src/org/labkey/api/data/JdbcType.java b/api/src/org/labkey/api/data/JdbcType.java index e0cd6aefa3a..b3d3e0220a1 100644 --- a/api/src/org/labkey/api/data/JdbcType.java +++ b/api/src/org/labkey/api/data/JdbcType.java @@ -53,7 +53,7 @@ public enum JdbcType @Override protected Object _fromNumber(Number n) { - return n.longValue(); + return _toLong(n); } @Override @@ -605,15 +605,22 @@ private static Boolean _toBoolean(Number n) return Boolean.FALSE; if (1 == n.intValue()) return Boolean.TRUE; - throw new ConversionException("Expected boolean value"); } + private static Long _toLong(Number n) + { + if (n instanceof Long l) + return l; + if (!(n instanceof BigDecimal) && n.doubleValue() == (double)n.longValue()) + return n.longValue(); + return ConvertHelper.convert(n, Long.class); + } private static Integer _toInt(Number n) { if (n.doubleValue() != (double)n.intValue()) - throw new ConversionException("Expected integer value"); + throw new ConversionException("Could not convert '" + n + "' to an integer"); return n.intValue(); } @@ -621,7 +628,7 @@ private static Integer _toInt(Number n) private static Short _toShort(Number n) { if (n.doubleValue() != (double)n.shortValue()) - throw new ConversionException("Expected integer value"); + throw new ConversionException("Could not convert '" + n + "' to a short integer"); return n.shortValue(); }