Coverage Report - liquibase.util.NumberUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
NumberUtils
0%
0/71
0%
0/64
12
 
 1  
 package liquibase.util;
 2  
 
 3  
 import java.math.BigDecimal;
 4  
 import java.math.BigInteger;
 5  
 import java.text.NumberFormat;
 6  
 import java.text.ParseException;
 7  
 
 8  
 /**
 9  
  * Miscellaneous utility methods for number conversion and parsing. Mainly for internal use within the framework;
 10  
  * consider Jakarta's Commons Lang for a more comprehensive suite of string utilities.
 11  
  * 
 12  
  * @author Juergen Hoeller
 13  
  * @author Rob Harrop
 14  
  * @since 1.1.2
 15  
  */
 16  0
 public abstract class NumberUtils {
 17  
 
 18  
     /**
 19  
      * Convert the given number into an instance of the given target class.
 20  
      * 
 21  
      * @param number
 22  
      *            the number to convert
 23  
      * @param targetClass
 24  
      *            the target class to convert to
 25  
      * @return the converted number
 26  
      * @throws IllegalArgumentException
 27  
      *             if the target class is not supported (i.e. not a standard Number subclass as included in the JDK)
 28  
      * @see java.lang.Byte
 29  
      * @see java.lang.Short
 30  
      * @see java.lang.Integer
 31  
      * @see java.lang.Long
 32  
      * @see java.math.BigInteger
 33  
      * @see java.lang.Float
 34  
      * @see java.lang.Double
 35  
      * @see java.math.BigDecimal
 36  
      */
 37  
     public static Number convertNumberToTargetClass(Number number, Class targetClass) throws IllegalArgumentException {
 38  
 
 39  0
         if (targetClass.isInstance(number)) {
 40  0
             return number;
 41  0
         } else if (targetClass.equals(Byte.class)) {
 42  0
             long value = number.longValue();
 43  0
             if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
 44  0
                 raiseOverflowException(number, targetClass);
 45  
             }
 46  0
             return number.byteValue();
 47  0
         } else if (targetClass.equals(Short.class)) {
 48  0
             long value = number.longValue();
 49  0
             if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
 50  0
                 raiseOverflowException(number, targetClass);
 51  
             }
 52  0
             return number.shortValue();
 53  0
         } else if (targetClass.equals(Integer.class)) {
 54  0
             long value = number.longValue();
 55  0
             if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
 56  0
                 raiseOverflowException(number, targetClass);
 57  
             }
 58  0
             return number.intValue();
 59  0
         } else if (targetClass.equals(Long.class)) {
 60  0
             return number.longValue();
 61  0
         } else if (targetClass.equals(Float.class)) {
 62  0
             return number.floatValue();
 63  0
         } else if (targetClass.equals(Double.class)) {
 64  0
             return number.doubleValue();
 65  0
         } else if (targetClass.equals(BigInteger.class)) {
 66  0
             return BigInteger.valueOf(number.longValue());
 67  0
         } else if (targetClass.equals(BigDecimal.class)) {
 68  
             // using BigDecimal(String) here, to avoid unpredictability of BigDecimal(double)
 69  
             // (see BigDecimal javadoc for details)
 70  0
             return new BigDecimal(number.toString());
 71  
         } else {
 72  0
             throw new IllegalArgumentException("Could not convert number [" + number + "] of type ["
 73  
                     + number.getClass().getName() + "] to unknown target class [" + targetClass.getName() + "]");
 74  
         }
 75  
     }
 76  
 
 77  
     /**
 78  
      * Raise an overflow exception for the given number and target class.
 79  
      * 
 80  
      * @param number
 81  
      *            the number we tried to convert
 82  
      * @param targetClass
 83  
      *            the target class we tried to convert to
 84  
      */
 85  
     private static void raiseOverflowException(Number number, Class targetClass) {
 86  0
         throw new IllegalArgumentException("Could not convert number [" + number + "] of type ["
 87  
                 + number.getClass().getName() + "] to target class [" + targetClass.getName() + "]: overflow");
 88  
     }
 89  
 
 90  
     /**
 91  
      * Parse the given text into a number instance of the given target class, using the corresponding default
 92  
      * <code>decode</code> methods. Trims the input <code>String</code> before attempting to parse the number. Supports
 93  
      * numbers in hex format (with leading 0x) and in octal format (with leading 0).
 94  
      * 
 95  
      * @param text
 96  
      *            the text to convert
 97  
      * @param targetClass
 98  
      *            the target class to parse into
 99  
      * @return the parsed number
 100  
      * @throws IllegalArgumentException
 101  
      *             if the target class is not supported (i.e. not a standard Number subclass as included in the JDK)
 102  
      * @see java.lang.Byte#decode
 103  
      * @see java.lang.Short#decode
 104  
      * @see java.lang.Integer#decode
 105  
      * @see java.lang.Long#decode
 106  
      * @see #decodeBigInteger(String)
 107  
      * @see java.lang.Float#valueOf
 108  
      * @see java.lang.Double#valueOf
 109  
      * @see java.math.BigDecimal#BigDecimal(String)
 110  
      */
 111  
     public static Number parseNumber(String text, Class targetClass) {
 112  0
         String trimmed = text.trim();
 113  
 
 114  0
         if (targetClass.equals(Byte.class)) {
 115  0
             return Byte.decode(trimmed);
 116  0
         } else if (targetClass.equals(Short.class)) {
 117  0
             return Short.decode(trimmed);
 118  0
         } else if (targetClass.equals(Integer.class)) {
 119  0
             return Integer.decode(trimmed);
 120  0
         } else if (targetClass.equals(Long.class)) {
 121  0
             return Long.decode(trimmed);
 122  0
         } else if (targetClass.equals(BigInteger.class)) {
 123  0
             return decodeBigInteger(trimmed);
 124  0
         } else if (targetClass.equals(Float.class)) {
 125  0
             return Float.valueOf(trimmed);
 126  0
         } else if (targetClass.equals(Double.class)) {
 127  0
             return Double.valueOf(trimmed);
 128  0
         } else if (targetClass.equals(BigDecimal.class) || targetClass.equals(Number.class)) {
 129  0
             return new BigDecimal(trimmed);
 130  
         } else {
 131  0
             throw new IllegalArgumentException("Cannot convert String [" + text + "] to target class ["
 132  
                     + targetClass.getName() + "]");
 133  
         }
 134  
     }
 135  
 
 136  
     /**
 137  
      * Parse the given text into a number instance of the given target class, using the given NumberFormat. Trims the
 138  
      * input <code>String</code> before attempting to parse the number.
 139  
      * 
 140  
      * @param text
 141  
      *            the text to convert
 142  
      * @param targetClass
 143  
      *            the target class to parse into
 144  
      * @param numberFormat
 145  
      *            the NumberFormat to use for parsing (if <code>null</code>, this method falls back to
 146  
      *            <code>parseNumber(String, Class)</code>)
 147  
      * @return the parsed number
 148  
      * @throws IllegalArgumentException
 149  
      *             if the target class is not supported (i.e. not a standard Number subclass as included in the JDK)
 150  
      * @see java.text.NumberFormat#parse
 151  
      * @see #convertNumberToTargetClass
 152  
      * @see #parseNumber(String,Class)
 153  
      */
 154  
     public static Number parseNumber(String text, Class targetClass, NumberFormat numberFormat) {
 155  0
         if (numberFormat != null) {
 156  
             try {
 157  0
                 Number number = numberFormat.parse(text.trim());
 158  0
                 return convertNumberToTargetClass(number, targetClass);
 159  0
             } catch (ParseException ex) {
 160  0
                 throw new IllegalArgumentException(ex.getMessage());
 161  
             }
 162  
         } else {
 163  0
             return parseNumber(text, targetClass);
 164  
         }
 165  
     }
 166  
 
 167  
     /**
 168  
      * Decode a {@link java.math.BigInteger} from a {@link String} value. Supports decimal, hex and octal notation.
 169  
      * 
 170  
      * @see BigInteger#BigInteger(String,int)
 171  
      */
 172  
     private static BigInteger decodeBigInteger(String value) {
 173  0
         int radix = 10;
 174  0
         int index = 0;
 175  0
         boolean negative = false;
 176  
 
 177  
         // Handle minus sign, if present.
 178  0
         if (value.startsWith("-")) {
 179  0
             negative = true;
 180  0
             index++;
 181  
         }
 182  
 
 183  
         // Handle radix specifier, if present.
 184  0
         if (value.startsWith("0x", index) || value.startsWith("0X", index)) {
 185  0
             index += 2;
 186  0
             radix = 16;
 187  0
         } else if (value.startsWith("#", index)) {
 188  0
             index++;
 189  0
             radix = 16;
 190  0
         } else if (value.startsWith("0", index) && value.length() > 1 + index) {
 191  0
             index++;
 192  0
             radix = 8;
 193  
         }
 194  
 
 195  0
         BigInteger result = new BigInteger(value.substring(index), radix);
 196  0
         return (negative ? result.negate() : result);
 197  
     }
 198  
 
 199  
 }