View Javadoc
1   package com.github.mygreen.supercsv.cellprocessor.format;
2   
3   import java.math.BigDecimal;
4   import java.math.BigInteger;
5   import java.math.MathContext;
6   import java.util.HashMap;
7   import java.util.Map;
8   import java.util.Objects;
9   
10  /**
11   * 書式がない数値のフォーマッタ。
12   *
13   * @since 2.0
14   * @author T.TSUCHIE
15   *
16   */
17  public class SimpleNumberFormatter<T extends Number> extends AbstractTextFormatter<T> {
18      
19      private final Class<T> type;
20      
21      private final boolean lenient;
22      
23      private final MathContext mathContext;
24      
25      /**
26       * デフォルトコンストラクタ
27       * @param type 数値のクラスタイプ
28       * @param lenient 曖昧にパースするかどうか。
29       * @throws NullPointerException {@literal type is null.}
30       * 
31       */
32      public SimpleNumberFormatter(final Class<T> type, final boolean lenient) {
33          this(type, lenient, null);
34          
35      }
36      
37      /**
38       * デフォルトコンストラクタ
39       * @param type 数値のクラスタイプ
40       * @param lenient 曖昧にパースするかどうか。
41       * @param mathContext 丸めの方法を指定します。nullを渡すと省略できます。
42       * @throws NullPointerException {@literal type is null.}
43       * 
44       */
45      public SimpleNumberFormatter(final Class<T> type, final boolean lenient, final MathContext mathContext) {
46          Objects.requireNonNull(type);
47          
48          this.type = type;
49          this.lenient = lenient;
50          this.mathContext = mathContext;
51          
52      }
53      
54      @SuppressWarnings("unchecked")
55      @Override
56      public T parse(final String text) {
57          
58          try {
59              final BigDecimal number = mathContext == null ? new BigDecimal(text) : new BigDecimal(text, mathContext);
60              return (T) parseFromBigDecimal(type, number);
61              
62          } catch(NumberFormatException | ArithmeticException e) {
63              throw new TextParseException(text, type, e);
64          }
65      }
66      
67      private Number parseFromBigDecimal(final Class<? extends Number> type, final BigDecimal number) {
68          
69          if(Byte.class.isAssignableFrom(type) || byte.class.isAssignableFrom(type)) {
70              return lenient ? number.byteValue() : number.byteValueExact();
71              
72          } else if(Short.class.isAssignableFrom(type) || short.class.isAssignableFrom(type)) {
73              return lenient ? number.shortValue() : number.shortValueExact();
74              
75          } else if(Integer.class.isAssignableFrom(type) || int.class.isAssignableFrom(type)) {
76              return lenient ? number.intValue() : number.intValueExact();
77              
78          } else if(Long.class.isAssignableFrom(type) || long.class.isAssignableFrom(type)) {
79              return lenient ? number.longValue() : number.longValueExact();
80              
81          } else if(Float.class.isAssignableFrom(type) || float.class.isAssignableFrom(type)) {
82              return number.floatValue();
83              
84          } else if(Double.class.isAssignableFrom(type) || double.class.isAssignableFrom(type)) {
85              return number.doubleValue();
86              
87          } else if(type.isAssignableFrom(BigInteger.class)) {
88              return lenient ? number.toBigInteger() : number.toBigIntegerExact();
89              
90          } else if(type.isAssignableFrom(BigDecimal.class)) {
91              return number;
92              
93          }
94          
95          throw new IllegalArgumentException(String.format("Not support class type : %s", type.getCanonicalName()));
96          
97      }
98      
99      @Override
100     public String print(final T object) {
101         
102         if(mathContext != null) {
103             return printNumber(object);
104         }
105         
106         return object.toString();
107     }
108     
109     private String printNumber(final Object object) {
110         
111         if(Byte.class.isAssignableFrom(type) || byte.class.isAssignableFrom(type)) {
112             return new BigDecimal((byte)object, mathContext).toPlainString();
113             
114         } else if(Short.class.isAssignableFrom(type) || short.class.isAssignableFrom(type)) {
115             return new BigDecimal((short)object, mathContext).toPlainString();
116             
117         } else if(Integer.class.isAssignableFrom(type) || int.class.isAssignableFrom(type)) {
118             return new BigDecimal((int)object, mathContext).toPlainString();
119             
120         } else if(Long.class.isAssignableFrom(type) || long.class.isAssignableFrom(type)) {
121             return new BigDecimal((long)object, mathContext).toPlainString();
122             
123         } else if(Float.class.isAssignableFrom(type) || float.class.isAssignableFrom(type)) {
124             return new BigDecimal((float)object, mathContext).toPlainString();
125             
126         } else if(Double.class.isAssignableFrom(type) || double.class.isAssignableFrom(type)) {
127             return new BigDecimal((double)object, mathContext).toPlainString();
128             
129         } else if(BigInteger.class.isAssignableFrom(type)) {
130             return new BigDecimal((BigInteger)object, mathContext).toPlainString();
131             
132         } else {
133             return object.toString();
134         }
135     }
136     
137     /**
138      * パースする際に、数値に変換可能な部分のみ変換するかどうか。
139      * <p>例えば、trueのときは、{@literal 123abc} をパースする際に{@literal 123}を数値としてパースします。
140      *   <br>falseの場合は、例外{@link TextParseException}をスローします。
141      * </p>
142      * @return trueの場合、曖昧にパースします。
143      */
144     public boolean isLenient() {
145         return lenient;
146     }
147     
148     /**
149      * パースする際の数値の丸め方法の指定情報を取得します。
150      * @return 数値の丸め方法
151      */
152     public MathContext getMathContext() {
153         return mathContext;
154     }
155     
156     @Override
157     public Map<String, Object> getMessageVariables() {
158         
159         final Map<String, Object> vars = new HashMap<>();
160         
161         if(mathContext != null) {
162             vars.put("precision", mathContext.getPrecision());
163         }
164         
165         return vars;
166     }
167     
168 }