1
2
3
4
5
6
7
8
9
10
11 package org.csveed.bean.conversion;
12
13 import static org.csveed.bean.conversion.ConversionUtil.trimAllWhitespace;
14
15 import java.math.BigDecimal;
16 import java.math.BigInteger;
17 import java.text.DecimalFormat;
18 import java.text.NumberFormat;
19 import java.text.ParseException;
20
21
22
23
24 public abstract class NumberUtils {
25
26
27
28
29 private NumberUtils() {
30
31 }
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 @SuppressWarnings("unchecked")
49 public static <T extends Number> T convertNumberToTargetClass(Number number, Class<T> targetClass)
50 throws IllegalArgumentException {
51
52 if (targetClass.isInstance(number)) {
53 return (T) number;
54 }
55 if (targetClass.equals(Byte.class)) {
56 long value = number.longValue();
57 if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
58 raiseOverflowException(number, targetClass);
59 }
60 return (T) Byte.valueOf(number.byteValue());
61 }
62 if (targetClass.equals(Short.class)) {
63 long value = number.longValue();
64 if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
65 raiseOverflowException(number, targetClass);
66 }
67 return (T) Short.valueOf(number.shortValue());
68 }
69 if (targetClass.equals(Integer.class)) {
70 long value = number.longValue();
71 if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
72 raiseOverflowException(number, targetClass);
73 }
74 return (T) Integer.valueOf(number.intValue());
75 }
76 if (targetClass.equals(Long.class)) {
77 return (T) Long.valueOf(number.longValue());
78 }
79 if (targetClass.equals(BigInteger.class)) {
80 if (number instanceof BigDecimal) {
81
82 return (T) ((BigDecimal) number).toBigInteger();
83 }
84
85 return (T) BigInteger.valueOf(number.longValue());
86 }
87 if (targetClass.equals(Float.class)) {
88 return (T) Float.valueOf(number.floatValue());
89 }
90 if (targetClass.equals(Double.class)) {
91 return (T) Double.valueOf(number.doubleValue());
92 }
93 if (targetClass.equals(BigDecimal.class)) {
94
95
96 return (T) new BigDecimal(number.toString());
97 }
98 throw new IllegalArgumentException("Could not convert number [" + number + "] of type ["
99 + number.getClass().getName() + "] to unknown target class [" + targetClass.getName() + "]");
100 }
101
102
103
104
105
106
107
108
109
110 private static void raiseOverflowException(Number number, Class targetClass) {
111 throw new IllegalArgumentException("Could not convert number [" + number + "] of type ["
112 + number.getClass().getName() + "] to target class [" + targetClass.getName() + "]: overflow");
113 }
114
115
116
117
118
119
120
121
122
123
124
125
126
127 @SuppressWarnings("unchecked")
128 public static <T extends Number> T parseNumber(String text, Class<T> targetClass) {
129 String trimmed = trimAllWhitespace(text);
130
131 if (targetClass.equals(Byte.class)) {
132 return (T) (isHexNumber(trimmed) ? Byte.decode(trimmed) : Byte.valueOf(trimmed));
133 }
134 if (targetClass.equals(Short.class)) {
135 return (T) (isHexNumber(trimmed) ? Short.decode(trimmed) : Short.valueOf(trimmed));
136 }
137 if (targetClass.equals(Integer.class)) {
138 return (T) (isHexNumber(trimmed) ? Integer.decode(trimmed) : Integer.valueOf(trimmed));
139 }
140 if (targetClass.equals(Long.class)) {
141 return (T) (isHexNumber(trimmed) ? Long.decode(trimmed) : Long.valueOf(trimmed));
142 }
143 if (targetClass.equals(BigInteger.class)) {
144 return (T) (isHexNumber(trimmed) ? decodeBigInteger(trimmed) : new BigInteger(trimmed));
145 }
146 if (targetClass.equals(Float.class)) {
147 return (T) Float.valueOf(trimmed);
148 }
149 if (targetClass.equals(Double.class)) {
150 return (T) Double.valueOf(trimmed);
151 }
152 if (targetClass.equals(BigDecimal.class) || targetClass.equals(Number.class)) {
153 return (T) new BigDecimal(trimmed);
154 }
155 throw new IllegalArgumentException(
156 "Cannot convert String [" + text + "] to target class [" + targetClass.getName() + "]");
157 }
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173 public static <T extends Number> T parseNumber(String text, Class<T> targetClass, NumberFormat numberFormat) {
174 if (numberFormat != null) {
175 DecimalFormat decimalFormat = null;
176 boolean resetBigDecimal = false;
177 if (numberFormat instanceof DecimalFormat) {
178 decimalFormat = (DecimalFormat) numberFormat;
179 if (BigDecimal.class.equals(targetClass) && !decimalFormat.isParseBigDecimal()) {
180 decimalFormat.setParseBigDecimal(true);
181 resetBigDecimal = true;
182 }
183 }
184 try {
185 Number number = numberFormat.parse(trimAllWhitespace(text));
186 return convertNumberToTargetClass(number, targetClass);
187 } catch (ParseException ex) {
188 throw new IllegalArgumentException("Could not parse number: " + ex.getMessage());
189 } finally {
190 if (resetBigDecimal && decimalFormat != null) {
191 decimalFormat.setParseBigDecimal(false);
192 }
193 }
194 }
195 return parseNumber(text, targetClass);
196 }
197
198
199
200
201
202
203
204
205
206 private static boolean isHexNumber(String value) {
207 int index = value.startsWith("-") ? 1 : 0;
208 return value.startsWith("0x", index) || value.startsWith("0X", index) || value.startsWith("#", index);
209 }
210
211
212
213
214
215
216
217
218
219 private static BigInteger decodeBigInteger(String value) {
220 int radix = 10;
221 int index = 0;
222 boolean negative = false;
223
224
225 if (value.startsWith("-")) {
226 negative = true;
227 index++;
228 }
229
230
231 if (value.startsWith("0x", index) || value.startsWith("0X", index)) {
232 index += 2;
233 radix = 16;
234 } else if (value.startsWith("#", index)) {
235 index++;
236 radix = 16;
237 } else if (value.startsWith("0", index) && value.length() > 1 + index) {
238 index++;
239 radix = 8;
240 }
241
242 BigInteger result = new BigInteger(value.substring(index), radix);
243 return negative ? result.negate() : result;
244 }
245
246 }