1 package com.github.mygreen.supercsv.cellprocessor.format;
2
3 import java.math.BigDecimal;
4 import java.math.BigInteger;
5 import java.text.DecimalFormat;
6 import java.text.NumberFormat;
7 import java.text.ParseException;
8 import java.text.ParsePosition;
9 import java.util.HashMap;
10 import java.util.Map;
11 import java.util.Objects;
12 import java.util.Optional;
13
14
15
16
17
18
19
20
21 public class NumberFormatWrapper<T extends Number> extends AbstractTextFormatter<T> {
22
23 private final NumberFormat formatter;
24
25 private final Class<T> type;
26
27 private final boolean lenient;
28
29 public NumberFormatWrapper(final NumberFormat formatter, final Class<T> type) {
30 this(formatter, type, false);
31 }
32
33 public NumberFormatWrapper(final NumberFormat formatter, final Class<T> type, final boolean lenient) {
34 Objects.requireNonNull(formatter);
35 Objects.requireNonNull(type);
36
37 this.formatter = (NumberFormat) formatter.clone();
38 this.type = type;
39 this.lenient = lenient;
40
41 }
42
43 @Override
44 public synchronized String print(final Number number) {
45 return formatter.format(number);
46 }
47
48 @Override
49 public T parse(final String text) {
50 return parse(type, text);
51 }
52
53
54
55
56
57
58
59
60
61
62
63 @SuppressWarnings("unchecked")
64 synchronized <N extends Number> N parse(final Class<N> type, final String text) {
65
66 final Number result;
67 if(lenient) {
68 try {
69 result = formatter.parse(text);
70 } catch(ParseException e) {
71 throw new TextParseException(text, type, e);
72 }
73 } else {
74 ParsePosition position = new ParsePosition(0);
75 result = formatter.parse(text, position);
76
77 if(position.getIndex() != text.length()) {
78 throw new TextParseException(text, type, String.format("Cannot parse '%s' using fromat %s", text, getPattern()));
79 }
80 }
81
82 try {
83 if(result instanceof BigDecimal) {
84
85 return (N) convertWithBigDecimal(type, (BigDecimal) result, text);
86
87 } else {
88 return (N) convertWithNumber(type, result, text);
89 }
90 } catch(NumberFormatException | ArithmeticException e) {
91 throw new TextParseException(text, type, e);
92 }
93
94 }
95
96 private Number convertWithNumber(final Class<? extends Number> type, final Number number, final String str) {
97
98 if(Byte.class.isAssignableFrom(type) || byte.class.isAssignableFrom(type)) {
99 return number.byteValue();
100
101 } else if(Short.class.isAssignableFrom(type) || short.class.isAssignableFrom(type)) {
102 return number.shortValue() ;
103
104 } else if(Integer.class.isAssignableFrom(type) || int.class.isAssignableFrom(type)) {
105 return number.intValue();
106
107 } else if(Long.class.isAssignableFrom(type) || long.class.isAssignableFrom(type)) {
108 return number.longValue();
109
110 } else if(Float.class.isAssignableFrom(type) || float.class.isAssignableFrom(type)) {
111 return number.floatValue();
112
113 } else if(Double.class.isAssignableFrom(type) || double.class.isAssignableFrom(type)) {
114 return number.doubleValue();
115
116 } else if(type.isAssignableFrom(BigInteger.class)) {
117 return new BigInteger(str);
118
119 } else if(type.isAssignableFrom(BigDecimal.class)) {
120 return new BigDecimal(str);
121
122 }
123
124 throw new IllegalArgumentException(String.format("not support class type : %s", type.getCanonicalName()));
125 }
126
127 private Number convertWithBigDecimal(final Class<? extends Number> type, final BigDecimal number, final String str) {
128
129 if(Byte.class.isAssignableFrom(type) || byte.class.isAssignableFrom(type)) {
130 return lenient ? number.byteValue() : number.byteValueExact();
131
132 } else if(Short.class.isAssignableFrom(type) || short.class.isAssignableFrom(type)) {
133 return lenient ? number.shortValue() : number.shortValueExact();
134
135 } else if(Integer.class.isAssignableFrom(type) || int.class.isAssignableFrom(type)) {
136 return lenient ? number.intValue() : number.intValueExact();
137
138 } else if(Long.class.isAssignableFrom(type) || long.class.isAssignableFrom(type)) {
139 return lenient ? number.longValue() : number.longValueExact();
140
141 } else if(Float.class.isAssignableFrom(type) || float.class.isAssignableFrom(type)) {
142 return number.floatValue();
143
144 } else if(Double.class.isAssignableFrom(type) || double.class.isAssignableFrom(type)) {
145 return number.doubleValue();
146
147 } else if(type.isAssignableFrom(BigInteger.class)) {
148 return lenient ? number.toBigInteger() : number.toBigIntegerExact();
149
150 } else if(type.isAssignableFrom(BigDecimal.class)) {
151 return number;
152
153 }
154
155 throw new IllegalArgumentException(String.format("not support class type : %s", type.getCanonicalName()));
156
157 }
158
159 @Override
160 public Optional<String> getPattern() {
161
162 if(formatter instanceof DecimalFormat) {
163 DecimalFormat df = (DecimalFormat) formatter;
164 return Optional.of(df.toPattern());
165 }
166
167 return Optional.empty();
168
169 }
170
171
172
173
174
175
176
177
178 public boolean isLenient() {
179 return lenient;
180 }
181
182 @Override
183 public Map<String, Object> getMessageVariables() {
184
185 final Map<String, Object> vars = new HashMap<>();
186 getPattern().ifPresent(p -> vars.put("pattern", p));
187
188 return vars;
189 }
190
191 }