1 package com.github.mygreen.supercsv.builder.standard;
2
3 import java.math.MathContext;
4 import java.math.RoundingMode;
5 import java.text.DecimalFormat;
6 import java.text.DecimalFormatSymbols;
7 import java.util.Currency;
8 import java.util.Locale;
9 import java.util.Optional;
10
11 import org.supercsv.cellprocessor.ift.CellProcessor;
12
13 import com.github.mygreen.supercsv.annotation.constraint.CsvNumberMax;
14 import com.github.mygreen.supercsv.annotation.constraint.CsvNumberMin;
15 import com.github.mygreen.supercsv.annotation.constraint.CsvNumberRange;
16 import com.github.mygreen.supercsv.annotation.format.CsvNumberFormat;
17 import com.github.mygreen.supercsv.builder.AbstractProcessorBuilder;
18 import com.github.mygreen.supercsv.builder.Configuration;
19 import com.github.mygreen.supercsv.builder.FieldAccessor;
20 import com.github.mygreen.supercsv.cellprocessor.constraint.NumberMaxFactory;
21 import com.github.mygreen.supercsv.cellprocessor.constraint.NumberMinFactory;
22 import com.github.mygreen.supercsv.cellprocessor.constraint.NumberRangeFactory;
23 import com.github.mygreen.supercsv.cellprocessor.format.NumberFormatWrapper;
24 import com.github.mygreen.supercsv.cellprocessor.format.SimpleNumberFormatter;
25 import com.github.mygreen.supercsv.cellprocessor.format.TextFormatter;
26 import com.github.mygreen.supercsv.util.Utils;
27
28
29
30
31
32
33
34
35
36
37 public abstract class AbstractNumberProcessorBuilder<N extends Number & Comparable<N>> extends AbstractProcessorBuilder<N> {
38
39 public AbstractNumberProcessorBuilder() {
40 super();
41
42 }
43
44 @Override
45 protected void init() {
46 super.init();
47
48
49 registerForConstraint(CsvNumberRange.class, new NumberRangeFactory<>());
50 registerForConstraint(CsvNumberMin.class, new NumberMinFactory<>());
51 registerForConstraint(CsvNumberMax.class, new NumberMaxFactory<>());
52
53
54 }
55
56 @Override
57 protected TextFormatter<N> getDefaultFormatter(final FieldAccessor field, final Configuration config) {
58
59 final Optional<NumberFormatWrapper<N>> formatter = createFormatter(field, config);
60 if(formatter.isPresent()) {
61 return formatter.get();
62
63 } else {
64 return createSimpleFormatter(field, config);
65
66 }
67
68 }
69
70
71
72
73
74
75
76
77 @SuppressWarnings("unchecked")
78 protected Optional<NumberFormatWrapper<N>> createFormatter(final FieldAccessor field, final Configuration config) {
79
80 final Optional<CsvNumberFormat> formatAnno = field.getAnnotation(CsvNumberFormat.class);
81
82 if(!formatAnno.isPresent()) {
83 return Optional.empty();
84 }
85
86 final String pattern = formatAnno.get().pattern();
87 if(pattern.isEmpty()) {
88 return Optional.empty();
89 }
90
91 final boolean lenient = formatAnno.get().lenient();
92 final Locale locale = Utils.getLocale(formatAnno.get().locale());
93 final Optional<Currency> currency = formatAnno.get().currency().isEmpty() ? Optional.empty()
94 : Optional.of(Currency.getInstance(formatAnno.get().currency()));
95 final RoundingMode roundingMode = formatAnno.get().rounding();
96 final DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale);
97
98 final DecimalFormat formatter = new DecimalFormat(pattern, symbols);
99 formatter.setParseBigDecimal(true);
100 formatter.setRoundingMode(roundingMode);
101 currency.ifPresent(c -> formatter.setCurrency(c));
102
103 final NumberFormatWrapper<N> wrapper = new NumberFormatWrapper<>(formatter, (Class<N>)field.getType(), lenient);
104 wrapper.setValidationMessage(formatAnno.get().message());
105
106 return Optional.of(wrapper);
107
108 }
109
110
111
112
113
114
115
116
117
118 @SuppressWarnings("unchecked")
119 protected SimpleNumberFormatter<N> createSimpleFormatter(final FieldAccessor field, final Configuration config) {
120
121 final Optional<CsvNumberFormat> formatAnno = field.getAnnotation(CsvNumberFormat.class);
122 if(!formatAnno.isPresent()) {
123 return new SimpleNumberFormatter<>((Class<N>)field.getType(), false);
124 }
125
126 final boolean lenient = formatAnno.get().lenient();
127 final RoundingMode roundingMode = formatAnno.get().rounding();
128 final int precision = formatAnno.get().precision();
129
130 final SimpleNumberFormatter<N> formatter;
131 if(precision >= 0) {
132 formatter = new SimpleNumberFormatter<>((Class<N>)field.getType(), lenient, new MathContext(precision, roundingMode));
133
134 } else {
135 formatter = new SimpleNumberFormatter<>((Class<N>)field.getType(), lenient);
136
137 }
138
139 formatter.setValidationMessage(formatAnno.get().message());
140
141 return formatter;
142
143 }
144
145 }