StringToNumberConverter.java
package fr.sii.ogham.core.convert;
import java.math.BigDecimal;
import java.math.BigInteger;
import fr.sii.ogham.core.exception.convert.ConversionException;
/**
* Converts a string to a number. It also handles {@link Byte}s. This class is
* copied from Spring.
*
* @author Aurélien Baudet
*
*/
public class StringToNumberConverter implements SupportingConverter {
@Override
public <T> T convert(Object source, Class<T> targetType) {
String text = (String) source;
String trimmed = trimAllWhitespace(text);
if(trimmed==null) {
return null;
}
try {
T value = convertNumber(trimmed, targetType);
if(value==null) {
throw new ConversionException("Cannot convert String [" + text + "] to target class [" + targetType.getName() + "]");
}
return value;
} catch(NumberFormatException e) {
throw new ConversionException("Failed to convert "+source+" to "+targetType.getSimpleName(), e);
}
}
@Override
public boolean supports(Class<?> sourceType, Class<?> targetType) {
return String.class.isAssignableFrom(sourceType) && Number.class.isAssignableFrom(targetType);
}
@SuppressWarnings("unchecked")
private <T> T convertNumber(String trimmed, Class<T> targetType) { // NOSONAR: code from Spring
if (Byte.class == targetType) {
return (T) (isHexOrOctalNumber(trimmed) ? Byte.decode(trimmed) : Byte.valueOf(trimmed));
}
if (Short.class == targetType) {
return (T) (isHexOrOctalNumber(trimmed) ? Short.decode(trimmed) : Short.valueOf(trimmed));
}
if (Integer.class == targetType) {
return (T) (isHexOrOctalNumber(trimmed) ? Integer.decode(trimmed) : Integer.valueOf(trimmed));
}
if (Long.class == targetType) {
return (T) (isHexOrOctalNumber(trimmed) ? Long.decode(trimmed) : Long.valueOf(trimmed));
}
if (BigInteger.class == targetType) {
return (T) (isHexOrOctalNumber(trimmed) ? decodeBigInteger(trimmed) : new BigInteger(trimmed));
}
if (Float.class == targetType) {
return (T) Float.valueOf(trimmed);
}
if (Double.class == targetType) {
return (T) Double.valueOf(trimmed);
}
if (BigDecimal.class == targetType || Number.class == targetType) {
return (T) new BigDecimal(trimmed);
}
return null;
}
private static boolean isHexOrOctalNumber(String value) {
int index = value.startsWith("-") ? 1 : 0;
return value.startsWith("#", index) || value.startsWith("0", index);
}
private static String trimAllWhitespace(String str) {
if (str == null || str.length() == 0) {
return null;
}
int len = str.length();
StringBuilder sb = new StringBuilder(str.length());
for (int i = 0; i < len; i++) {
char c = str.charAt(i);
if (!Character.isWhitespace(c)) {
sb.append(c);
}
}
return sb.toString();
}
private static BigInteger decodeBigInteger(String value) {
int radix = 10;
int index = 0;
boolean negative = false;
// Handle minus sign, if present.
if (value.startsWith("-")) {
negative = true;
index++;
}
// Handle radix specifier, if present.
if (value.startsWith("0x", index) || value.startsWith("0X", index)) {
index += 2;
radix = 16;
} else if (value.startsWith("#", index)) {
index++;
radix = 16;
} else if (value.startsWith("0", index) && value.length() > 1 + index) {
index++;
radix = 8;
}
BigInteger result = new BigInteger(value.substring(index), radix);
return negative ? result.negate() : result;
}
}