NumberUtils consistently raises overflow exception for BigInteger/BigDecimal input
Issue: SPR-14041
This commit is contained in:
parent
431ca9314a
commit
1ca4340271
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -87,39 +87,29 @@ public abstract class NumberUtils {
|
||||||
return (T) number;
|
return (T) number;
|
||||||
}
|
}
|
||||||
else if (Byte.class == targetClass) {
|
else if (Byte.class == targetClass) {
|
||||||
long value = number.longValue();
|
long value = checkedLongValue(number, targetClass);
|
||||||
if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
|
if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
|
||||||
raiseOverflowException(number, targetClass);
|
raiseOverflowException(number, targetClass);
|
||||||
}
|
}
|
||||||
return (T) Byte.valueOf(number.byteValue());
|
return (T) Byte.valueOf(number.byteValue());
|
||||||
}
|
}
|
||||||
else if (Short.class == targetClass) {
|
else if (Short.class == targetClass) {
|
||||||
long value = number.longValue();
|
long value = checkedLongValue(number, targetClass);
|
||||||
if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
|
if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
|
||||||
raiseOverflowException(number, targetClass);
|
raiseOverflowException(number, targetClass);
|
||||||
}
|
}
|
||||||
return (T) Short.valueOf(number.shortValue());
|
return (T) Short.valueOf(number.shortValue());
|
||||||
}
|
}
|
||||||
else if (Integer.class == targetClass) {
|
else if (Integer.class == targetClass) {
|
||||||
long value = number.longValue();
|
long value = checkedLongValue(number, targetClass);
|
||||||
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
|
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
|
||||||
raiseOverflowException(number, targetClass);
|
raiseOverflowException(number, targetClass);
|
||||||
}
|
}
|
||||||
return (T) Integer.valueOf(number.intValue());
|
return (T) Integer.valueOf(number.intValue());
|
||||||
}
|
}
|
||||||
else if (Long.class == targetClass) {
|
else if (Long.class == targetClass) {
|
||||||
BigInteger bigInt = null;
|
long value = checkedLongValue(number, targetClass);
|
||||||
if (number instanceof BigInteger) {
|
return (T) Long.valueOf(value);
|
||||||
bigInt = (BigInteger) number;
|
|
||||||
}
|
|
||||||
else if (number instanceof BigDecimal) {
|
|
||||||
bigInt = ((BigDecimal) number).toBigInteger();
|
|
||||||
}
|
|
||||||
// Effectively analogous to JDK 8's BigInteger.longValueExact()
|
|
||||||
if (bigInt != null && (bigInt.compareTo(LONG_MIN) < 0 || bigInt.compareTo(LONG_MAX) > 0)) {
|
|
||||||
raiseOverflowException(number, targetClass);
|
|
||||||
}
|
|
||||||
return (T) Long.valueOf(number.longValue());
|
|
||||||
}
|
}
|
||||||
else if (BigInteger.class == targetClass) {
|
else if (BigInteger.class == targetClass) {
|
||||||
if (number instanceof BigDecimal) {
|
if (number instanceof BigDecimal) {
|
||||||
|
|
@ -148,11 +138,35 @@ public abstract class NumberUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for a {@code BigInteger}/{@code BigDecimal} long overflow
|
||||||
|
* before returning the given number as a long value.
|
||||||
|
* @param number the number to convert
|
||||||
|
* @param targetClass the target class to convert to
|
||||||
|
* @return the long value, if convertible without overflow
|
||||||
|
* @throws IllegalArgumentException if there is an overflow
|
||||||
|
* @see #raiseOverflowException
|
||||||
|
*/
|
||||||
|
private static long checkedLongValue(Number number, Class<? extends Number> targetClass) {
|
||||||
|
BigInteger bigInt = null;
|
||||||
|
if (number instanceof BigInteger) {
|
||||||
|
bigInt = (BigInteger) number;
|
||||||
|
}
|
||||||
|
else if (number instanceof BigDecimal) {
|
||||||
|
bigInt = ((BigDecimal) number).toBigInteger();
|
||||||
|
}
|
||||||
|
// Effectively analogous to JDK 8's BigInteger.longValueExact()
|
||||||
|
if (bigInt != null && (bigInt.compareTo(LONG_MIN) < 0 || bigInt.compareTo(LONG_MAX) > 0)) {
|
||||||
|
raiseOverflowException(number, targetClass);
|
||||||
|
}
|
||||||
|
return number.longValue();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raise an <em>overflow</em> exception for the given number and target class.
|
* Raise an <em>overflow</em> exception for the given number and target class.
|
||||||
* @param number the number we tried to convert
|
* @param number the number we tried to convert
|
||||||
* @param targetClass the target class we tried to convert to
|
* @param targetClass the target class we tried to convert to
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException if there is an overflow
|
||||||
*/
|
*/
|
||||||
private static void raiseOverflowException(Number number, Class<?> targetClass) {
|
private static void raiseOverflowException(Number number, Class<?> targetClass) {
|
||||||
throw new IllegalArgumentException("Could not convert number [" + number + "] of type [" +
|
throw new IllegalArgumentException("Could not convert number [" + number + "] of type [" +
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -328,8 +328,6 @@ public class NumberUtilsTests {
|
||||||
assertEquals(Integer.valueOf(Integer.MIN_VALUE), NumberUtils.convertNumberToTargetClass(BigInteger.valueOf(Integer.MAX_VALUE + 1), Integer.class));
|
assertEquals(Integer.valueOf(Integer.MIN_VALUE), NumberUtils.convertNumberToTargetClass(BigInteger.valueOf(Integer.MAX_VALUE + 1), Integer.class));
|
||||||
assertEquals(Integer.valueOf(Integer.MIN_VALUE), NumberUtils.convertNumberToTargetClass(BigInteger.valueOf(Integer.MIN_VALUE), Integer.class));
|
assertEquals(Integer.valueOf(Integer.MIN_VALUE), NumberUtils.convertNumberToTargetClass(BigInteger.valueOf(Integer.MIN_VALUE), Integer.class));
|
||||||
assertEquals(Integer.valueOf(Integer.MAX_VALUE), NumberUtils.convertNumberToTargetClass(BigInteger.valueOf(Integer.MIN_VALUE - 1), Integer.class));
|
assertEquals(Integer.valueOf(Integer.MAX_VALUE), NumberUtils.convertNumberToTargetClass(BigInteger.valueOf(Integer.MIN_VALUE - 1), Integer.class));
|
||||||
assertToNumberOverflow(BigInteger.valueOf(Integer.MAX_VALUE).add(BigInteger.ONE), Integer.class);
|
|
||||||
assertToNumberOverflow(BigInteger.valueOf(Integer.MIN_VALUE).subtract(BigInteger.ONE), Integer.class);
|
|
||||||
|
|
||||||
assertEquals(Integer.valueOf(Integer.valueOf(-1)), NumberUtils.convertNumberToTargetClass(Long.valueOf(-1), Integer.class));
|
assertEquals(Integer.valueOf(Integer.valueOf(-1)), NumberUtils.convertNumberToTargetClass(Long.valueOf(-1), Integer.class));
|
||||||
assertEquals(Integer.valueOf(Integer.valueOf(0)), NumberUtils.convertNumberToTargetClass(Long.valueOf(0), Integer.class));
|
assertEquals(Integer.valueOf(Integer.valueOf(0)), NumberUtils.convertNumberToTargetClass(Long.valueOf(0), Integer.class));
|
||||||
|
|
@ -338,8 +336,6 @@ public class NumberUtilsTests {
|
||||||
assertEquals(Integer.valueOf(Integer.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Long.valueOf(Integer.MAX_VALUE + 1), Integer.class));
|
assertEquals(Integer.valueOf(Integer.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Long.valueOf(Integer.MAX_VALUE + 1), Integer.class));
|
||||||
assertEquals(Integer.valueOf(Integer.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Long.valueOf(Integer.MIN_VALUE), Integer.class));
|
assertEquals(Integer.valueOf(Integer.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Long.valueOf(Integer.MIN_VALUE), Integer.class));
|
||||||
assertEquals(Integer.valueOf(Integer.MAX_VALUE), NumberUtils.convertNumberToTargetClass(Long.valueOf(Integer.MIN_VALUE - 1), Integer.class));
|
assertEquals(Integer.valueOf(Integer.MAX_VALUE), NumberUtils.convertNumberToTargetClass(Long.valueOf(Integer.MIN_VALUE - 1), Integer.class));
|
||||||
assertToNumberOverflow(Long.valueOf(Long.MAX_VALUE + 1), Integer.class);
|
|
||||||
assertToNumberOverflow(Long.valueOf(Long.MIN_VALUE - 1), Integer.class);
|
|
||||||
|
|
||||||
assertEquals(Integer.valueOf(Integer.valueOf(-1)), NumberUtils.convertNumberToTargetClass(Integer.valueOf(-1), Integer.class));
|
assertEquals(Integer.valueOf(Integer.valueOf(-1)), NumberUtils.convertNumberToTargetClass(Integer.valueOf(-1), Integer.class));
|
||||||
assertEquals(Integer.valueOf(Integer.valueOf(0)), NumberUtils.convertNumberToTargetClass(Integer.valueOf(0), Integer.class));
|
assertEquals(Integer.valueOf(Integer.valueOf(0)), NumberUtils.convertNumberToTargetClass(Integer.valueOf(0), Integer.class));
|
||||||
|
|
@ -364,6 +360,12 @@ public class NumberUtilsTests {
|
||||||
assertEquals(Integer.valueOf(Byte.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf((byte) (Byte.MAX_VALUE + 1)), Integer.class));
|
assertEquals(Integer.valueOf(Byte.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf((byte) (Byte.MAX_VALUE + 1)), Integer.class));
|
||||||
assertEquals(Integer.valueOf(Byte.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf(Byte.MIN_VALUE), Integer.class));
|
assertEquals(Integer.valueOf(Byte.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf(Byte.MIN_VALUE), Integer.class));
|
||||||
assertEquals(Integer.valueOf(Byte.MAX_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf((byte) (Byte.MIN_VALUE - 1)), Integer.class));
|
assertEquals(Integer.valueOf(Byte.MAX_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf((byte) (Byte.MIN_VALUE - 1)), Integer.class));
|
||||||
|
|
||||||
|
assertToNumberOverflow(Long.valueOf(Long.MAX_VALUE + 1), Integer.class);
|
||||||
|
assertToNumberOverflow(Long.valueOf(Long.MIN_VALUE - 1), Integer.class);
|
||||||
|
assertToNumberOverflow(BigInteger.valueOf(Integer.MAX_VALUE).add(BigInteger.ONE), Integer.class);
|
||||||
|
assertToNumberOverflow(BigInteger.valueOf(Integer.MIN_VALUE).subtract(BigInteger.ONE), Integer.class);
|
||||||
|
assertToNumberOverflow(new BigDecimal("18446744073709551611"), Integer.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -376,9 +378,6 @@ public class NumberUtilsTests {
|
||||||
assertEquals(Long.valueOf(Long.MIN_VALUE), NumberUtils.convertNumberToTargetClass(BigInteger.valueOf(Long.MIN_VALUE), Long.class));
|
assertEquals(Long.valueOf(Long.MIN_VALUE), NumberUtils.convertNumberToTargetClass(BigInteger.valueOf(Long.MIN_VALUE), Long.class));
|
||||||
assertEquals(Long.valueOf(Long.MAX_VALUE), NumberUtils.convertNumberToTargetClass(BigInteger.valueOf(Long.MIN_VALUE - 1), Long.class));
|
assertEquals(Long.valueOf(Long.MAX_VALUE), NumberUtils.convertNumberToTargetClass(BigInteger.valueOf(Long.MIN_VALUE - 1), Long.class));
|
||||||
|
|
||||||
assertToNumberOverflow(BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE), Long.class);
|
|
||||||
assertToNumberOverflow(BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.ONE), Long.class);
|
|
||||||
|
|
||||||
assertEquals(Long.valueOf(Long.valueOf(-1)), NumberUtils.convertNumberToTargetClass(Long.valueOf(-1), Long.class));
|
assertEquals(Long.valueOf(Long.valueOf(-1)), NumberUtils.convertNumberToTargetClass(Long.valueOf(-1), Long.class));
|
||||||
assertEquals(Long.valueOf(Long.valueOf(0)), NumberUtils.convertNumberToTargetClass(Long.valueOf(0), Long.class));
|
assertEquals(Long.valueOf(Long.valueOf(0)), NumberUtils.convertNumberToTargetClass(Long.valueOf(0), Long.class));
|
||||||
assertEquals(Long.valueOf(Long.valueOf(1)), NumberUtils.convertNumberToTargetClass(Long.valueOf(1), Long.class));
|
assertEquals(Long.valueOf(Long.valueOf(1)), NumberUtils.convertNumberToTargetClass(Long.valueOf(1), Long.class));
|
||||||
|
|
@ -410,6 +409,10 @@ public class NumberUtilsTests {
|
||||||
assertEquals(Long.valueOf(Byte.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf((byte) (Byte.MAX_VALUE + 1)), Long.class));
|
assertEquals(Long.valueOf(Byte.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf((byte) (Byte.MAX_VALUE + 1)), Long.class));
|
||||||
assertEquals(Long.valueOf(Byte.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf(Byte.MIN_VALUE), Long.class));
|
assertEquals(Long.valueOf(Byte.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf(Byte.MIN_VALUE), Long.class));
|
||||||
assertEquals(Long.valueOf(Byte.MAX_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf((byte) (Byte.MIN_VALUE - 1)), Long.class));
|
assertEquals(Long.valueOf(Byte.MAX_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf((byte) (Byte.MIN_VALUE - 1)), Long.class));
|
||||||
|
|
||||||
|
assertToNumberOverflow(BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE), Long.class);
|
||||||
|
assertToNumberOverflow(BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.ONE), Long.class);
|
||||||
|
assertToNumberOverflow(new BigDecimal("18446744073709551611"), Long.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue