View Javadoc
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   * 数値型に対する{@link CellProcessor}を組み立てるクラス。
31   * <p>各種タイプごとに実装を行う。</p>
32   * 
33   * @version 2.0
34   * @author T.TSUCHIE
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       * <p>アノテーション{@link CsvNumberFormat}の値を元に作成します。</p>
73       * @param field フィールド情報
74       * @param config システム設定
75       * @return アノテーション{@link CsvNumberFormat}が付与されていない場合は、空を返す。
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      * アノテーション{@link CsvNumberFormat}の指定がないときなどの書式のない数値のフォーマッタの作成。
112      * <p>{@link #createFormatter(FieldAccessor, Configuration)}で結果が空の時に使用する。</p>
113      * 
114      * @param field フィールド情報
115      * @param config システム設定
116      * @return
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 }