org.jopendocument.util.convertor.NumberConvertor Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2008 jOpenDocument, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU
* General Public License Version 3 only ("GPL").
* You may not use this file except in compliance with the License.
* You can obtain a copy of the License at http://www.gnu.org/licenses/gpl-3.0.html
* See the License for the specific language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*
*/
package org.jopendocument.util.convertor;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
public abstract class NumberConvertor implements ValueConvertor {
public static final NumberConvertor INT_TO_LONG = new NumberConvertor() {
@Override
public Long convert(Integer o) {
return o.longValue();
}
@Override
public Integer unconvert(Long o) {
return o.intValue();
}
};
public static final NumberConvertor SHORT_TO_INT = new NumberConvertor() {
@Override
public Integer convert(Short o) {
return o.intValue();
}
@Override
public Short unconvert(Integer o) {
return o.shortValue();
}
};
public static final NumberConvertor create(final Class c1, final Class c2, final boolean exact) {
return new NumberConvertor() {
@Override
public N2 convert(N1 o) {
return exact ? convertExact(o, c2) : convert(o, c2);
}
@Override
public N1 unconvert(N2 o) {
return exact ? convertExact(o, c1) : convert(o, c1);
}
};
}
/**
* Convert from one class of {@link Number} to another. Necessary since new Integer(123) isn't
* equal to new Long(123).
*
* @param type of desired Number.
* @param n the instance to convert, e.g. new Integer(123).
* @param clazz desired class of Number, e.g. Long.class.
* @return n as an instance of clazz, e.g. new Long(123).
*/
public static N convert(Number n, Class clazz) {
final Number res;
if (n == null || n.getClass() == clazz || clazz == Number.class) {
res = n;
} else if (clazz == Short.class) {
res = n.shortValue();
} else if (clazz == Integer.class) {
res = n.intValue();
} else if (clazz == Long.class) {
res = n.longValue();
} else if (clazz == Byte.class) {
res = n.byteValue();
} else if (clazz == BigInteger.class) {
if (n instanceof BigDecimal)
res = ((BigDecimal) n).toBigInteger();
else if (n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof AtomicInteger || n instanceof Long || n instanceof AtomicLong)
res = BigInteger.valueOf(n.longValue());
else if (n instanceof Float || n instanceof Double)
res = BigDecimal.valueOf(n.doubleValue()).toBigInteger();
else
res = new BigInteger(n.toString());
} else if (clazz == AtomicInteger.class) {
res = new AtomicInteger(n.intValue());
} else if (clazz == AtomicLong.class) {
res = new AtomicLong(n.longValue());
} else if (clazz == BigDecimal.class) {
res = toBigDecimal(n);
} else if (clazz == Double.class) {
res = n.doubleValue();
} else if (clazz == Float.class) {
res = n.floatValue();
} else {
throw new IllegalArgumentException("unknown class: " + clazz);
}
return clazz.cast(res);
}
public static BigDecimal toBigDecimal(final Number n) {
final BigDecimal res;
if (n == null || n instanceof BigDecimal) {
res = (BigDecimal) n;
} else if (n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof AtomicInteger || n instanceof Long || n instanceof AtomicLong) {
res = BigDecimal.valueOf(n.longValue());
} else if (n instanceof Float || n instanceof Double) {
res = BigDecimal.valueOf(n.doubleValue());
} else if (n instanceof BigInteger) {
res = new BigDecimal((BigInteger) n);
} else {
res = new BigDecimal(n.toString());
}
return res;
}
public static class OverflowException extends ArithmeticException {
public OverflowException(Number n, Class extends Number> clazz) {
super("Cannot convert to " + clazz + " : " + n);
}
@Override
public OverflowException initCause(Throwable cause) {
super.initCause(cause);
return this;
}
}
public static class RoundingException extends ArithmeticException {
public RoundingException(Number n, Class extends Number> clazz) {
super("Rounding necessary for " + clazz + " : " + n + " (" + n.getClass() + ")");
}
}
public static final BigDecimal MAX_FLOAT = BigDecimal.valueOf(Float.MAX_VALUE);
public static final BigDecimal MIN_FLOAT = MAX_FLOAT.negate();
public static final BigDecimal MAX_DOUBLE = BigDecimal.valueOf(Double.MAX_VALUE);
public static final BigDecimal MIN_DOUBLE = MAX_DOUBLE.negate();
public static N convertExact(Number n, Class clazz) throws OverflowException, RoundingException {
final Number res;
if (n == null || n.getClass() == clazz || clazz == Number.class) {
res = n;
} else if (n instanceof BigDecimal) {
// cannot use *ValueExact() since we want to differentiate between overflow and rounding
final BigDecimal bd = (BigDecimal) n;
if (clazz == Byte.class || clazz == Short.class || clazz == Integer.class || clazz == AtomicInteger.class || clazz == Long.class || clazz == AtomicLong.class || clazz == BigInteger.class) {
final BigInteger bi;
try {
bi = bd.toBigIntegerExact();
} catch (ArithmeticException e) {
throw new RoundingException(n, clazz);
}
if (clazz == BigInteger.class) {
res = bi;
} else {
try {
res = convertExact(bi, clazz);
} catch (RoundingException e) {
// cannot be a rounding error since we pass a BigInteger
throw new IllegalStateException(e);
} catch (OverflowException e) {
throw new OverflowException(n, clazz).initCause(e);
}
}
} else if (clazz == Float.class) {
if (bd.compareTo(MAX_FLOAT) > 0 || bd.compareTo(MIN_FLOAT) < 0)
throw new OverflowException(n, clazz);
res = n.floatValue();
} else if (clazz == Double.class) {
if (bd.compareTo(MAX_DOUBLE) > 0 || bd.compareTo(MIN_DOUBLE) < 0)
throw new OverflowException(n, clazz);
res = n.doubleValue();
} else {
throw new IllegalStateException("Unknown class " + n.getClass());
}
} else if (clazz == Byte.class) {
final byte value = n.byteValue();
if (n instanceof Short || n instanceof Integer || n instanceof AtomicInteger || n instanceof Long || n instanceof AtomicLong) {
if (value != n.longValue())
throw new OverflowException(n, clazz);
} else if (n instanceof BigInteger) {
if (((BigInteger) n).bitLength() >= Byte.SIZE)
throw new OverflowException(n, clazz);
} else if (n instanceof Float || n instanceof Double) {
if (n.doubleValue() > Byte.MAX_VALUE || n.doubleValue() < Byte.MIN_VALUE)
throw new OverflowException(n, clazz);
else
throw new RoundingException(n, clazz);
} else {
throw new IllegalStateException("Unknown class " + n.getClass());
}
res = value;
} else if (clazz == Short.class) {
final short value = n.shortValue();
if (n instanceof Integer || n instanceof AtomicInteger || n instanceof Long || n instanceof AtomicLong) {
if (value != n.longValue())
throw new OverflowException(n, clazz);
} else if (n instanceof Byte) {
} else if (n instanceof BigInteger) {
if (((BigInteger) n).bitLength() >= Short.SIZE)
throw new OverflowException(n, clazz);
} else if (n instanceof Float || n instanceof Double) {
if (n.doubleValue() > Short.MAX_VALUE || n.doubleValue() < Short.MIN_VALUE)
throw new OverflowException(n, clazz);
else
throw new RoundingException(n, clazz);
} else {
throw new IllegalStateException("Unknown class " + n.getClass());
}
res = value;
} else if (clazz == Integer.class || clazz == AtomicInteger.class) {
final int value = n.intValue();
if (n instanceof Long || n instanceof AtomicLong) {
if (value != n.longValue())
throw new OverflowException(n, clazz);
} else if (n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof AtomicInteger) {
} else if (n instanceof BigInteger) {
if (((BigInteger) n).bitLength() >= Integer.SIZE)
throw new OverflowException(n, clazz);
} else if (n instanceof Float || n instanceof Double) {
if (n.doubleValue() > Integer.MAX_VALUE || n.doubleValue() < Integer.MIN_VALUE)
throw new OverflowException(n, clazz);
else
throw new RoundingException(n, clazz);
} else {
throw new IllegalStateException("Unknown class " + n.getClass());
}
res = clazz == Integer.class ? Integer.valueOf(value) : new AtomicInteger(value);
} else if (clazz == Long.class || clazz == AtomicLong.class) {
final long value = n.longValue();
if (n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof AtomicInteger || n instanceof Long || n instanceof AtomicLong) {
} else if (n instanceof BigInteger) {
if (((BigInteger) n).bitLength() >= Long.SIZE)
throw new OverflowException(n, clazz);
} else if (n instanceof Float || n instanceof Double) {
// at the limits of Long, Double have less than one unit of precision, so since both
// case of this if throw exceptions, be lenient to allow testing the limits
if (n.doubleValue() >= Long.MAX_VALUE || n.doubleValue() <= Long.MIN_VALUE)
throw new OverflowException(n, clazz);
else
throw new RoundingException(n, clazz);
} else {
throw new IllegalStateException("Unknown class " + n.getClass());
}
res = clazz == Long.class ? Long.valueOf(value) : new AtomicLong(value);
} else if (clazz == BigInteger.class) {
if (n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof AtomicInteger || n instanceof Long || n instanceof AtomicLong) {
} else if (n instanceof Float || n instanceof Double) {
throw new RoundingException(n, clazz);
} else {
throw new IllegalStateException("Unknown class " + n.getClass());
}
res = BigInteger.valueOf(n.longValue());
} else if (clazz == BigDecimal.class) {
res = toBigDecimal(n);
} else if (clazz == Double.class) {
if (n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof AtomicInteger || n instanceof Long || n instanceof AtomicLong || n instanceof Float) {
} else if (n instanceof BigInteger) {
final BigInteger bi = (BigInteger) n;
// can use toBigIntegerExact() since the precision is low at the limits
if (bi.compareTo(MAX_DOUBLE.toBigIntegerExact()) > 0 || bi.compareTo(MIN_DOUBLE.toBigIntegerExact()) < 0)
throw new OverflowException(n, clazz);
} else {
throw new IllegalStateException("Unknown class " + n.getClass());
}
res = n.doubleValue();
} else if (clazz == Float.class) {
if (n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof AtomicInteger || n instanceof Long || n instanceof AtomicLong) {
} else if (n instanceof Double) {
if (Math.abs(n.doubleValue()) > Float.MAX_VALUE)
throw new OverflowException(n, clazz);
} else if (n instanceof BigInteger) {
final BigInteger bi = (BigInteger) n;
// can use toBigIntegerExact() since the precision is low at the limits
if (bi.compareTo(MAX_FLOAT.toBigIntegerExact()) > 0 || bi.compareTo(MIN_FLOAT.toBigIntegerExact()) < 0)
throw new OverflowException(n, clazz);
} else {
throw new IllegalStateException("Unknown class " + n.getClass());
}
res = n.floatValue();
} else {
throw new IllegalArgumentException("Unknown class: " + clazz);
}
return clazz.cast(res);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy