1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.batch.item.file.transform;
18
19 import java.math.BigDecimal;
20 import java.text.DateFormat;
21 import java.text.DecimalFormat;
22 import java.text.NumberFormat;
23 import java.text.ParseException;
24 import java.text.SimpleDateFormat;
25 import java.util.Arrays;
26 import java.util.Date;
27 import java.util.List;
28 import java.util.Locale;
29 import java.util.Properties;
30
31 import org.springframework.util.Assert;
32 import org.springframework.util.StringUtils;
33
34
35
36
37
38
39
40
41
42 public class DefaultFieldSet implements FieldSet {
43
44 private final static String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";
45
46 private DateFormat dateFormat = new SimpleDateFormat(DEFAULT_DATE_PATTERN);
47 {
48 dateFormat.setLenient(false);
49 }
50
51 private NumberFormat numberFormat = NumberFormat.getInstance(Locale.US);
52
53 private String grouping = ",";
54
55 private String decimal = ".";
56
57
58
59
60 private String[] tokens;
61
62 private List<String> names;
63
64
65
66
67
68
69 public final void setNumberFormat(NumberFormat numberFormat) {
70 this.numberFormat = numberFormat;
71 if (numberFormat instanceof DecimalFormat) {
72 grouping = "" + ((DecimalFormat) numberFormat).getDecimalFormatSymbols().getGroupingSeparator();
73 decimal = "" + ((DecimalFormat) numberFormat).getDecimalFormatSymbols().getDecimalSeparator();
74 }
75 }
76
77
78
79
80
81
82 public void setDateFormat(DateFormat dateFormat) {
83 this.dateFormat = dateFormat;
84 }
85
86
87
88
89
90
91
92 public DefaultFieldSet(String[] tokens) {
93 this.tokens = tokens == null ? null : (String[]) tokens.clone();
94 setNumberFormat(NumberFormat.getInstance(Locale.US));
95 }
96
97
98
99
100
101
102
103
104 public DefaultFieldSet(String[] tokens, String[] names) {
105 Assert.notNull(tokens);
106 Assert.notNull(names);
107 if (tokens.length != names.length) {
108 throw new IllegalArgumentException("Field names must be same length as values: names="
109 + Arrays.asList(names) + ", values=" + Arrays.asList(tokens));
110 }
111 this.tokens = (String[]) tokens.clone();
112 this.names = Arrays.asList(names);
113 setNumberFormat(NumberFormat.getInstance(Locale.US));
114 }
115
116
117
118
119
120
121 public String[] getNames() {
122 if (names == null) {
123 throw new IllegalStateException("Field names are not known");
124 }
125 return names.toArray(new String[names.size()]);
126 }
127
128
129
130
131
132
133 public boolean hasNames() {
134 return names != null;
135 }
136
137
138
139
140
141
142 public String[] getValues() {
143 return tokens.clone();
144 }
145
146
147
148
149
150
151
152 public String readString(int index) {
153 return readAndTrim(index);
154 }
155
156
157
158
159
160
161
162
163 public String readString(String name) {
164 return readString(indexOf(name));
165 }
166
167
168
169
170
171
172
173 public String readRawString(int index) {
174 return tokens[index];
175 }
176
177
178
179
180
181
182
183
184 public String readRawString(String name) {
185 return readRawString(indexOf(name));
186 }
187
188
189
190
191
192
193
194 public boolean readBoolean(int index) {
195 return readBoolean(index, "true");
196 }
197
198
199
200
201
202
203
204
205 public boolean readBoolean(String name) {
206 return readBoolean(indexOf(name));
207 }
208
209
210
211
212
213
214
215
216 public boolean readBoolean(int index, String trueValue) {
217 Assert.notNull(trueValue, "'trueValue' cannot be null.");
218
219 String value = readAndTrim(index);
220
221 return trueValue.equals(value) ? true : false;
222 }
223
224
225
226
227
228
229
230
231 public boolean readBoolean(String name, String trueValue) {
232 return readBoolean(indexOf(name), trueValue);
233 }
234
235
236
237
238
239
240 public char readChar(int index) {
241 String value = readAndTrim(index);
242
243 Assert.isTrue(value.length() == 1, "Cannot convert field value '" + value + "' to char.");
244
245 return value.charAt(0);
246 }
247
248
249
250
251
252
253
254
255 public char readChar(String name) {
256 return readChar(indexOf(name));
257 }
258
259
260
261
262
263
264 public byte readByte(int index) {
265 return Byte.parseByte(readAndTrim(index));
266 }
267
268
269
270
271
272
273
274
275 public byte readByte(String name) {
276 return readByte(indexOf(name));
277 }
278
279
280
281
282
283
284 public short readShort(int index) {
285 return Short.parseShort(readAndTrim(index));
286 }
287
288
289
290
291
292
293
294
295 public short readShort(String name) {
296 return readShort(indexOf(name));
297 }
298
299
300
301
302
303
304 public int readInt(int index) {
305 return parseNumber(readAndTrim(index)).intValue();
306 }
307
308
309
310
311
312
313
314
315 public int readInt(String name) {
316 return readInt(indexOf(name));
317 }
318
319
320
321
322
323
324
325 public int readInt(int index, int defaultValue) {
326 String value = readAndTrim(index);
327
328 return StringUtils.hasLength(value) ? Integer.parseInt(value) : defaultValue;
329 }
330
331
332
333
334
335
336
337
338 public int readInt(String name, int defaultValue) {
339 return readInt(indexOf(name), defaultValue);
340 }
341
342
343
344
345
346
347 public long readLong(int index) {
348 return parseNumber(readAndTrim(index)).longValue();
349 }
350
351
352
353
354
355
356
357
358 public long readLong(String name) {
359 return readLong(indexOf(name));
360 }
361
362
363
364
365
366
367
368 public long readLong(int index, long defaultValue) {
369 String value = readAndTrim(index);
370
371 return StringUtils.hasLength(value) ? Long.parseLong(value) : defaultValue;
372 }
373
374
375
376
377
378
379
380
381 public long readLong(String name, long defaultValue) {
382 return readLong(indexOf(name), defaultValue);
383 }
384
385
386
387
388
389
390 public float readFloat(int index) {
391 return parseNumber(readAndTrim(index)).floatValue();
392 }
393
394
395
396
397
398
399
400
401 public float readFloat(String name) {
402 return readFloat(indexOf(name));
403 }
404
405
406
407
408
409
410
411 public double readDouble(int index) {
412 return (Double) parseNumber(readAndTrim(index)).doubleValue();
413 }
414
415
416
417
418
419
420
421
422 public double readDouble(String name) {
423 return readDouble(indexOf(name));
424 }
425
426
427
428
429
430
431
432 public BigDecimal readBigDecimal(int index) {
433 return readBigDecimal(index, null);
434 }
435
436
437
438
439
440
441
442
443 public BigDecimal readBigDecimal(String name) {
444 return readBigDecimal(name, null);
445 }
446
447
448
449
450
451
452
453
454 public BigDecimal readBigDecimal(int index, BigDecimal defaultValue) {
455 String candidate = readAndTrim(index);
456
457 if (!StringUtils.hasText(candidate)) {
458 return defaultValue;
459 }
460
461 try {
462 String result = removeSeparators(candidate);
463 return new BigDecimal(result);
464 }
465 catch (NumberFormatException e) {
466 throw new NumberFormatException("Unparseable number: " + candidate);
467 }
468 }
469
470 private String removeSeparators(String candidate) {
471 return candidate.replace(grouping, "").replace(decimal, ".");
472 }
473
474
475
476
477
478
479
480
481 public BigDecimal readBigDecimal(String name, BigDecimal defaultValue) {
482 try {
483 return readBigDecimal(indexOf(name), defaultValue);
484 }
485 catch (NumberFormatException e) {
486 throw new NumberFormatException(e.getMessage() + ", name: [" + name + "]");
487 }
488 catch (IllegalArgumentException e) {
489 throw new IllegalArgumentException(e.getMessage() + ", name: [" + name + "]");
490 }
491 }
492
493
494
495
496
497
498 public Date readDate(int index) {
499 return parseDate(readAndTrim(index), dateFormat);
500 }
501
502
503
504
505
506
507
508 public Date readDate(int index, Date defaultValue) {
509 try {
510 return readDate(index);
511 }
512 catch (IllegalArgumentException e) {
513 return defaultValue;
514 }
515 }
516
517
518
519
520
521
522
523
524 public Date readDate(String name) {
525 try {
526 return readDate(indexOf(name));
527 }
528 catch (IllegalArgumentException e) {
529 throw new IllegalArgumentException(e.getMessage() + ", name: [" + name + "]");
530 }
531 }
532
533
534
535
536
537
538
539 public Date readDate(String name, Date defaultValue) {
540 try {
541 return readDate(name);
542 }
543 catch (IllegalArgumentException e) {
544 return defaultValue;
545 }
546 }
547
548
549
550
551
552
553
554 public Date readDate(int index, String pattern) {
555 SimpleDateFormat sdf = new SimpleDateFormat(pattern);
556 sdf.setLenient(false);
557 return parseDate(readAndTrim(index), sdf);
558 }
559
560
561
562
563
564
565
566 public Date readDate(int index, String pattern, Date defaultValue) {
567 try {
568 return readDate(index, pattern);
569 }
570 catch (IllegalArgumentException e) {
571 return defaultValue;
572 }
573 }
574
575
576
577
578
579
580
581
582 public Date readDate(String name, String pattern) {
583 try {
584 return readDate(indexOf(name), pattern);
585 }
586 catch (IllegalArgumentException e) {
587 throw new IllegalArgumentException(e.getMessage() + ", name: [" + name + "]");
588 }
589 }
590
591
592
593
594
595
596
597 public Date readDate(String name, String pattern, Date defaultValue) {
598 try {
599 return readDate(name, pattern);
600 }
601 catch (IllegalArgumentException e) {
602 return defaultValue;
603 }
604 }
605
606
607
608
609
610
611
612 public int getFieldCount() {
613 return tokens.length;
614 }
615
616
617
618
619
620
621 protected String readAndTrim(int index) {
622 String value = tokens[index];
623
624 if (value != null) {
625 return value.trim();
626 }
627 else {
628 return null;
629 }
630 }
631
632
633
634
635
636
637
638
639 protected int indexOf(String name) {
640 if (names == null) {
641 throw new IllegalArgumentException("Cannot access columns by name without meta data");
642 }
643 int index = names.indexOf(name);
644 if (index >= 0) {
645 return index;
646 }
647 throw new IllegalArgumentException("Cannot access column [" + name + "] from " + names);
648 }
649
650 public String toString() {
651 if (names != null) {
652 return getProperties().toString();
653 }
654
655 return tokens == null ? "" : Arrays.asList(tokens).toString();
656 }
657
658
659
660
661 public boolean equals(Object object) {
662 if (object instanceof DefaultFieldSet) {
663 DefaultFieldSet fs = (DefaultFieldSet) object;
664
665 if (this.tokens == null) {
666 return fs.tokens == null;
667 }
668 else {
669 return Arrays.equals(this.tokens, fs.tokens);
670 }
671 }
672
673 return false;
674 }
675
676 public int hashCode() {
677
678 if (tokens == null) {
679 return 0;
680 }
681
682 int result = 1;
683
684 for (int i = 0; i < tokens.length; i++) {
685 result = 31 * result + (tokens[i] == null ? 0 : tokens[i].hashCode());
686 }
687
688 return result;
689 }
690
691
692
693
694
695
696
697 public Properties getProperties() {
698 if (names == null) {
699 throw new IllegalStateException("Cannot create properties without meta data");
700 }
701 Properties props = new Properties();
702 for (int i = 0; i < tokens.length; i++) {
703 String value = readAndTrim(i);
704 if (value != null) {
705 props.setProperty((String) names.get(i), value);
706 }
707 }
708 return props;
709 }
710
711 private Number parseNumber(String candidate) {
712 try {
713 return numberFormat.parse(candidate);
714 }
715 catch (ParseException e) {
716 throw new NumberFormatException("Unparseable number: " + candidate);
717 }
718 }
719
720 private Date parseDate(String readAndTrim, DateFormat dateFormat) {
721 try {
722 return dateFormat.parse(readAndTrim);
723 }
724 catch (ParseException e) {
725 String pattern;
726 if (dateFormat instanceof SimpleDateFormat) {
727 pattern = ((SimpleDateFormat) dateFormat).toPattern();
728 }
729 else {
730 pattern = dateFormat.toString();
731 }
732 throw new IllegalArgumentException(e.getMessage() + ", format: [" + pattern + "]");
733 }
734 }
735
736 }