diff --git a/src/main/java/org/apache/commons/validator/routines/BigIntegerValidator.java b/src/main/java/org/apache/commons/validator/routines/BigIntegerValidator.java index 27c44735f..1642d66cc 100644 --- a/src/main/java/org/apache/commons/validator/routines/BigIntegerValidator.java +++ b/src/main/java/org/apache/commons/validator/routines/BigIntegerValidator.java @@ -16,6 +16,7 @@ */ package org.apache.commons.validator.routines; +import java.math.BigDecimal; import java.math.BigInteger; import java.text.Format; import java.text.NumberFormat; @@ -120,7 +121,7 @@ public BigIntegerValidator(final boolean strict, final int formatType) { * specified range. */ public boolean isInRange(final BigInteger value, final long min, final long max) { - return value.longValue() >= min && value.longValue() <= max; + return value.compareTo(BigInteger.valueOf(min)) >= 0 && value.compareTo(BigInteger.valueOf(max)) <= 0; } /** @@ -132,7 +133,7 @@ public boolean isInRange(final BigInteger value, final long min, final long max) * or equal to the maximum. */ public boolean maxValue(final BigInteger value, final long max) { - return value.longValue() <= max; + return value.compareTo(BigInteger.valueOf(max)) <= 0; } /** @@ -157,7 +158,14 @@ public boolean minValue(final BigInteger value, final long min) { */ @Override protected Object processParsedValue(final Object value, final Format formatter) { - return BigInteger.valueOf(((Number) value).longValue()); + if (value instanceof Long) { + return BigInteger.valueOf(((Long) value).longValue()); + } + if (value instanceof Double) { + // No need to roundtrip with a string. + return BigDecimal.valueOf(((Double) value).doubleValue()).toBigInteger(); + } + return new BigDecimal(value.toString()).toBigInteger(); } /** diff --git a/src/test/java/org/apache/commons/validator/routines/BigIntegerValidatorTest.java b/src/test/java/org/apache/commons/validator/routines/BigIntegerValidatorTest.java index 8c2416d12..53ab62631 100644 --- a/src/test/java/org/apache/commons/validator/routines/BigIntegerValidatorTest.java +++ b/src/test/java/org/apache/commons/validator/routines/BigIntegerValidatorTest.java @@ -70,6 +70,50 @@ protected void setUp() { } + /** + * Test a value larger than {@link Long#MAX_VALUE} keeps its magnitude instead of being clamped to {@link Long#MAX_VALUE}. + */ + @Test + void testBigIntegerAboveLongMaxValue() { + // One past Long.MAX_VALUE, so NumberFormat parses it as a Double rather than a Long. + final BigInteger aboveLong = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE); + final String aboveLongStr = aboveLong.toString(); + final BigIntegerValidator instance = BigIntegerValidator.getInstance(); + final BigInteger resultAboveLong = instance.validate(aboveLongStr, "#"); + assertTrue(resultAboveLong.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) > 0); + assertTrue(resultAboveLong.compareTo(BigInteger.ZERO) > 0); + assertTrue(resultAboveLong.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0); + assertTrue(instance.minValue(resultAboveLong, Long.MIN_VALUE)); + assertFalse(instance.minValue(resultAboveLong, Long.MAX_VALUE)); + assertFalse(instance.maxValue(resultAboveLong, Long.MIN_VALUE)); + assertFalse(instance.maxValue(resultAboveLong, Long.MAX_VALUE)); + assertFalse(instance.isInRange(resultAboveLong, Long.MIN_VALUE, Long.MAX_VALUE)); + // BigDecimalValidator already preserves the magnitude, so the two must agree + assertEquals(BigDecimalValidator.getInstance().validate(aboveLongStr, "#").toBigInteger(), resultAboveLong); + } + + /** + * Test a value larger than {@link Long#MAX_VALUE} keeps its magnitude instead of being clamped to {@link Long#MAX_VALUE}. + */ + @Test + void testBigIntegerBelowLongMinValue() { + // One past Long.MAX_VALUE, so NumberFormat parses it as a Double rather than a Long. + final BigInteger belowLong = BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.ONE); + final String belowLongStr = belowLong.toString(); + final BigIntegerValidator instance = BigIntegerValidator.getInstance(); + final BigInteger resultBelowLong = instance.validate(belowLongStr, "#"); + assertTrue(resultBelowLong.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0); + assertTrue(resultBelowLong.compareTo(BigInteger.ZERO) < 0); + assertTrue(resultBelowLong.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) < 0); + assertTrue(instance.minValue(resultBelowLong, Long.MIN_VALUE)); + assertFalse(instance.minValue(resultBelowLong, Long.MAX_VALUE)); + assertTrue(instance.maxValue(resultBelowLong, Long.MIN_VALUE)); + assertTrue(instance.maxValue(resultBelowLong, Long.MAX_VALUE)); + assertFalse(instance.isInRange(resultBelowLong, Long.MIN_VALUE, Long.MAX_VALUE)); + // BigDecimalValidator already preserves the magnitude, so the two must agree + assertEquals(BigDecimalValidator.getInstance().validate(belowLongStr, "#").toBigInteger(), resultBelowLong); + } + /** * Test BigInteger Range/Min/Max */