diff --git a/api/src/org/labkey/api/data/ConvertHelper.java b/api/src/org/labkey/api/data/ConvertHelper.java index 516c30dbc57..4f104bf92f6 100644 --- a/api/src/org/labkey/api/data/ConvertHelper.java +++ b/api/src/org/labkey/api/data/ConvertHelper.java @@ -89,6 +89,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.Callable; /** @@ -1371,9 +1372,75 @@ public void testMiscConversions() assertEquals(home.getRowId(), ((Container)ConvertUtils.convert(home.getId(), Container.class)).getRowId()); assertEquals(home.getId(), ConvertUtils.convert(home, 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() +// Note: Keep in sync with LabKeySiteWrapper.getConversionErrorMessage() // Example: "Could not convert value '2.34' (Double) for Boolean field 'Medical History.Dep Diagnosed in Last 18 Months'" public static String getStandardConversionErrorMessage(Object value, String fieldName, Class expectedClass) { diff --git a/api/src/org/labkey/api/data/JdbcType.java b/api/src/org/labkey/api/data/JdbcType.java index 771dc7387aa..9b5184744e6 100644 --- a/api/src/org/labkey/api/data/JdbcType.java +++ b/api/src/org/labkey/api/data/JdbcType.java @@ -55,9 +55,7 @@ public enum JdbcType implements SimpleConvert @Override protected Object _fromNumber(Number n) { - if (n.doubleValue() == (double) n.longValue()) - return n.longValue(); - return null; // fallback + return _toLong(n); } @Override @@ -730,15 +728,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(); } @@ -746,7 +751,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(); }