1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.beanutils.converters;
18
19 import java.math.BigDecimal;
20 import java.math.BigInteger;
21 import java.text.DecimalFormat;
22 import java.text.DecimalFormatSymbols;
23 import java.text.NumberFormat;
24 import java.text.ParsePosition;
25 import java.util.Calendar;
26 import java.util.Date;
27 import java.util.Locale;
28
29 import org.apache.commons.beanutils.ConversionException;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85 public abstract class NumberConverter extends AbstractConverter {
86
87 private static final Integer ZERO = new Integer(0);
88 private static final Integer ONE = new Integer(1);
89
90 private String pattern;
91 private final boolean allowDecimals;
92 private boolean useLocaleFormat;
93 private Locale locale;
94
95
96
97
98
99
100
101
102
103 public NumberConverter(final boolean allowDecimals) {
104 super();
105 this.allowDecimals = allowDecimals;
106 }
107
108
109
110
111
112
113
114
115 public NumberConverter(final boolean allowDecimals, final Object defaultValue) {
116 super();
117 this.allowDecimals = allowDecimals;
118 setDefaultValue(defaultValue);
119 }
120
121
122
123
124
125
126
127
128 public boolean isAllowDecimals() {
129 return allowDecimals;
130 }
131
132
133
134
135
136
137
138
139 public void setUseLocaleFormat(final boolean useLocaleFormat) {
140 this.useLocaleFormat = useLocaleFormat;
141 }
142
143
144
145
146
147
148
149
150
151
152
153 public String getPattern() {
154 return pattern;
155 }
156
157
158
159
160
161
162
163
164
165
166 public void setPattern(final String pattern) {
167 this.pattern = pattern;
168 setUseLocaleFormat(true);
169 }
170
171
172
173
174
175
176
177 public Locale getLocale() {
178 return locale;
179 }
180
181
182
183
184
185
186 public void setLocale(final Locale locale) {
187 this.locale = locale;
188 setUseLocaleFormat(true);
189 }
190
191
192
193
194
195
196
197
198
199
200 @Override
201 protected String convertToString(final Object value) throws Throwable {
202
203 String result = null;
204 if (useLocaleFormat && value instanceof Number) {
205 final NumberFormat format = getFormat();
206 format.setGroupingUsed(false);
207 result = format.format(value);
208 if (log().isDebugEnabled()) {
209 log().debug(" Converted to String using format '" + result + "'");
210 }
211
212 } else {
213 result = value.toString();
214 if (log().isDebugEnabled()) {
215 log().debug(" Converted to String using toString() '" + result + "'");
216 }
217 }
218 return result;
219
220 }
221
222
223
224
225
226
227
228
229
230
231
232 @Override
233 protected <T> T convertToType(final Class<T> targetType, final Object value) throws Throwable {
234
235 final Class<?> sourceType = value.getClass();
236
237 if (value instanceof Number) {
238 return toNumber(sourceType, targetType, (Number)value);
239 }
240
241
242 if (value instanceof Boolean) {
243 return toNumber(sourceType, targetType, ((Boolean)value).booleanValue() ? ONE : ZERO);
244 }
245
246
247 if (value instanceof Date && Long.class.equals(targetType)) {
248 return targetType.cast(new Long(((Date)value).getTime()));
249 }
250
251
252 if (value instanceof Calendar && Long.class.equals(targetType)) {
253 return targetType.cast(new Long(((Calendar)value).getTime().getTime()));
254 }
255
256
257 final String stringValue = value.toString().trim();
258 if (stringValue.length() == 0) {
259 return handleMissing(targetType);
260 }
261
262
263 Number number = null;
264 if (useLocaleFormat) {
265 final NumberFormat format = getFormat();
266 number = parse(sourceType, targetType, stringValue, format);
267 } else {
268 if (log().isDebugEnabled()) {
269 log().debug(" No NumberFormat, using default conversion");
270 }
271 number = toNumber(sourceType, targetType, stringValue);
272 }
273
274
275 return toNumber(sourceType, targetType, number);
276
277 }
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300 private <T> T toNumber(final Class<?> sourceType, final Class<T> targetType, final Number value) {
301
302
303 if (targetType.equals(value.getClass())) {
304 return targetType.cast(value);
305 }
306
307
308 if (targetType.equals(Byte.class)) {
309 final long longValue = value.longValue();
310 if (longValue > Byte.MAX_VALUE) {
311 throw new ConversionException(toString(sourceType) + " value '" + value
312 + "' is too large for " + toString(targetType));
313 }
314 if (longValue < Byte.MIN_VALUE) {
315 throw new ConversionException(toString(sourceType) + " value '" + value
316 + "' is too small " + toString(targetType));
317 }
318 return targetType.cast(new Byte(value.byteValue()));
319 }
320
321
322 if (targetType.equals(Short.class)) {
323 final long longValue = value.longValue();
324 if (longValue > Short.MAX_VALUE) {
325 throw new ConversionException(toString(sourceType) + " value '" + value
326 + "' is too large for " + toString(targetType));
327 }
328 if (longValue < Short.MIN_VALUE) {
329 throw new ConversionException(toString(sourceType) + " value '" + value
330 + "' is too small " + toString(targetType));
331 }
332 return targetType.cast(new Short(value.shortValue()));
333 }
334
335
336 if (targetType.equals(Integer.class)) {
337 final long longValue = value.longValue();
338 if (longValue > Integer.MAX_VALUE) {
339 throw new ConversionException(toString(sourceType) + " value '" + value
340 + "' is too large for " + toString(targetType));
341 }
342 if (longValue < Integer.MIN_VALUE) {
343 throw new ConversionException(toString(sourceType) + " value '" + value
344 + "' is too small " + toString(targetType));
345 }
346 return targetType.cast(new Integer(value.intValue()));
347 }
348
349
350 if (targetType.equals(Long.class)) {
351 return targetType.cast(new Long(value.longValue()));
352 }
353
354
355 if (targetType.equals(Float.class)) {
356 if (value.doubleValue() > Float.MAX_VALUE) {
357 throw new ConversionException(toString(sourceType) + " value '" + value
358 + "' is too large for " + toString(targetType));
359 }
360 return targetType.cast(new Float(value.floatValue()));
361 }
362
363
364 if (targetType.equals(Double.class)) {
365 return targetType.cast(new Double(value.doubleValue()));
366 }
367
368
369 if (targetType.equals(BigDecimal.class)) {
370 if (value instanceof Float || value instanceof Double) {
371 return targetType.cast(new BigDecimal(value.toString()));
372 } else if (value instanceof BigInteger) {
373 return targetType.cast(new BigDecimal((BigInteger)value));
374 } else if (value instanceof BigDecimal) {
375 return targetType.cast(new BigDecimal(value.toString()));
376 } else {
377 return targetType.cast(BigDecimal.valueOf(value.longValue()));
378 }
379 }
380
381
382 if (targetType.equals(BigInteger.class)) {
383 if (value instanceof BigDecimal) {
384 return targetType.cast(((BigDecimal)value).toBigInteger());
385 } else {
386 return targetType.cast(BigInteger.valueOf(value.longValue()));
387 }
388 }
389
390 final String msg = toString(getClass()) + " cannot handle conversion to '"
391 + toString(targetType) + "'";
392 if (log().isWarnEnabled()) {
393 log().warn(" " + msg);
394 }
395 throw new ConversionException(msg);
396
397 }
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419 private Number toNumber(final Class<?> sourceType, final Class<?> targetType, final String value) {
420
421
422 if (targetType.equals(Byte.class)) {
423 return new Byte(value);
424 }
425
426
427 if (targetType.equals(Short.class)) {
428 return new Short(value);
429 }
430
431
432 if (targetType.equals(Integer.class)) {
433 return new Integer(value);
434 }
435
436
437 if (targetType.equals(Long.class)) {
438 return new Long(value);
439 }
440
441
442 if (targetType.equals(Float.class)) {
443 return new Float(value);
444 }
445
446
447 if (targetType.equals(Double.class)) {
448 return new Double(value);
449 }
450
451
452 if (targetType.equals(BigDecimal.class)) {
453 return new BigDecimal(value);
454 }
455
456
457 if (targetType.equals(BigInteger.class)) {
458 return new BigInteger(value);
459 }
460
461 final String msg = toString(getClass()) + " cannot handle conversion from '" +
462 toString(sourceType) + "' to '" + toString(targetType) + "'";
463 if (log().isWarnEnabled()) {
464 log().warn(" " + msg);
465 }
466 throw new ConversionException(msg);
467 }
468
469
470
471
472
473
474 @Override
475 public String toString() {
476 final StringBuilder buffer = new StringBuilder();
477 buffer.append(toString(getClass()));
478 buffer.append("[UseDefault=");
479 buffer.append(isUseDefault());
480 buffer.append(", UseLocaleFormat=");
481 buffer.append(useLocaleFormat);
482 if (pattern != null) {
483 buffer.append(", Pattern=");
484 buffer.append(pattern);
485 }
486 if (locale != null) {
487 buffer.append(", Locale=");
488 buffer.append(locale);
489 }
490 buffer.append(']');
491 return buffer.toString();
492 }
493
494
495
496
497
498
499 private NumberFormat getFormat() {
500 NumberFormat format = null;
501 if (pattern != null) {
502 if (locale == null) {
503 if (log().isDebugEnabled()) {
504 log().debug(" Using pattern '" + pattern + "'");
505 }
506 format = new DecimalFormat(pattern);
507 } else {
508 if (log().isDebugEnabled()) {
509 log().debug(" Using pattern '" + pattern + "'" +
510 " with Locale[" + locale + "]");
511 }
512 final DecimalFormatSymbols symbols = new DecimalFormatSymbols(locale);
513 format = new DecimalFormat(pattern, symbols);
514 }
515 } else {
516 if (locale == null) {
517 if (log().isDebugEnabled()) {
518 log().debug(" Using default Locale format");
519 }
520 format = NumberFormat.getInstance();
521 } else {
522 if (log().isDebugEnabled()) {
523 log().debug(" Using Locale[" + locale + "] format");
524 }
525 format = NumberFormat.getInstance(locale);
526 }
527 }
528 if (!allowDecimals) {
529 format.setParseIntegerOnly(true);
530 }
531 return format;
532 }
533
534
535
536
537
538
539
540
541
542
543
544 private Number parse(final Class<?> sourceType, final Class<?> targetType, final String value, final NumberFormat format) {
545 final ParsePosition pos = new ParsePosition(0);
546 final Number parsedNumber = format.parse(value, pos);
547 if (pos.getErrorIndex() >= 0 || pos.getIndex() != value.length() || parsedNumber == null) {
548 String msg = "Error converting from '" + toString(sourceType) + "' to '" + toString(targetType) + "'";
549 if (format instanceof DecimalFormat) {
550 msg += " using pattern '" + ((DecimalFormat)format).toPattern() + "'";
551 }
552 if (locale != null) {
553 msg += " for locale=[" + locale + "]";
554 }
555 if (log().isDebugEnabled()) {
556 log().debug(" " + msg);
557 }
558 throw new ConversionException(msg);
559 }
560 return parsedNumber;
561 }
562
563 }