NumberUtils consistently raises overflow exception for BigInteger/BigDecimal input

Issue: SPR-14041
This commit is contained in:
Juergen Hoeller
2016-03-18 18:51:41 +01:00
parent 431ca9314a
commit 1ca4340271
2 changed files with 42 additions and 25 deletions

View File

@@ -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");
* you may not use this file except in compliance with the License.
@@ -87,39 +87,29 @@ public abstract class NumberUtils {
return (T) number;
}
else if (Byte.class == targetClass) {
long value = number.longValue();
long value = checkedLongValue(number, targetClass);
if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
raiseOverflowException(number, targetClass);
}
return (T) Byte.valueOf(number.byteValue());
}
else if (Short.class == targetClass) {
long value = number.longValue();
long value = checkedLongValue(number, targetClass);
if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
raiseOverflowException(number, targetClass);
}
return (T) Short.valueOf(number.shortValue());
}
else if (Integer.class == targetClass) {
long value = number.longValue();
long value = checkedLongValue(number, targetClass);
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
raiseOverflowException(number, targetClass);
}
return (T) Integer.valueOf(number.intValue());
}
else if (Long.class == 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 (T) Long.valueOf(number.longValue());
long value = checkedLongValue(number, targetClass);
return (T) Long.valueOf(value);
}
else if (BigInteger.class == targetClass) {
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.
* @param number the number we tried to convert
* @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) {
throw new IllegalArgumentException("Could not convert number [" + number + "] of type [" +