View Javadoc
1   package com.github.mygreen.supercsv.io;
2   
3   import java.util.function.Supplier;
4   
5   import org.supercsv.encoder.CsvEncoder;
6   import org.supercsv.prefs.CsvPreference;
7   import org.supercsv.util.CsvContext;
8   
9   import com.github.mygreen.supercsv.builder.BeanMapping;
10  import com.github.mygreen.supercsv.builder.FixedSizeColumnProperty;
11  import com.github.mygreen.supercsv.exception.SuperCsvFixedSizeException;
12  
13  
14  /**
15   * 固定長CSVを書き込むときのCsvEncoder。
16   * <p>固定長サイズを超える場合は、例外 {@link SuperCsvFixedSizeException} をスローします。</p>
17   * <p>改行コードを含む場合は、例外外 {@link SuperCsvFixedSizeException} をスローします。</p>
18   *
19   * @param <T> マッピング対象のBeanのクラスタイプ
20   * @since 2.5
21   * @author T.TSUCHIE
22   *
23   */
24  public class FixedSizeCsvEncoder<T> implements CsvEncoder {
25  
26      /**
27       * BeanMappingの情報
28       * <p>CsvEncoderのインスタンス作成時は、BeanMappingのインスタンスは未作成のため遅延評価する。
29       */
30      private final Supplier<BeanMapping<T>> beanMappingSupplier;
31      
32      /**
33       * コンストラクタ。
34       * 
35       * @param beanMappingSupplier BeanMappingの情報を取得するためのSupplier。
36       * <p>CsvEncoderのインスタンス作成時は、BeanMappingのインスタンスは未作成のため遅延評価する。</p>
37       */
38      public FixedSizeCsvEncoder(Supplier<BeanMapping<T>> beanMappingSupplier) {
39          this.beanMappingSupplier = beanMappingSupplier;
40      }
41      
42      /**
43       * 指定した列番号のカラムの固定長プロパティを取得する。
44       * <p>列番号は1から始まる。</p>
45       * 
46       * @param columnNumber 列番号
47       * @return 固定長プロパティ
48       * @throws IllegalStateException 列番号に対応するカラムの情報が見つからない場合。
49       */
50      private FixedSizeColumnProperty getColumnProperty(int columnNumber) {
51          BeanMapping<T> beanMapping = beanMappingSupplier.get();
52          return beanMapping.getColumnMapping(columnNumber)
53                  .orElseThrow(() -> new IllegalStateException("columnMappings not found with columnNumber=" + columnNumber))
54                  .getFixedSizeProperty();
55      }
56      
57      /**
58       * 
59       * {@inheritDoc}
60       * @throws SuperCsvFixedSizeException 固定長サイズを超えたとき、または、改行コードを含む場合。
61       */
62      @Override
63      public String encode(final String input, final CsvContext context, final CsvPreference preference) {
64          
65          FixedSizeColumnProperty fixedSizeProperty = getColumnProperty(context.getColumnNumber());
66          
67          /*
68           * 固定長サイズと一致しない場合は例外をスローする。
69           * ※固定長サイズを超える場合は、使用者側で事前に切り落としておく。
70           */
71          int actualSize = fixedSizeProperty.getPaddingProcessor().count(input);
72          if (actualSize > fixedSizeProperty.getSize()) {
73              throw new SuperCsvFixedSizeException.Builder("csvError.fixedSizeOver", context)
74                      .messageFormat("Over column size. fixedColumnSize: %d, actualSize: %d",
75                              fixedSizeProperty.getSize(), actualSize)
76                      .messageVariables("fixedColumnSize", fixedSizeProperty.getSize())
77                      .messageVariables("actualSize", actualSize)
78                      .messageVariables("validatedValue", input)
79                      .build();
80          }
81          
82          /*
83           * 改行コードを含む場合は例外をスローする。
84           * ※改行コードを含む場合は、使用者側で事前に除去しておく。
85           */
86          if (input.contains("\r") || input.contains("\n")) {
87              throw new SuperCsvFixedSizeException.Builder("csvError.fixedSizeContainsLineBreak", context)
88                      .messageFormat("Contains line break. input: [%s]", input)
89                      .messageVariables("validatedValue", input)
90                      .build();
91          }
92          
93          // 囲み文字のエスケープなどは行わない。
94          return input;
95      }
96  }