AbstractProcessorBuilder.java
package com.github.mygreen.supercsv.builder;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.supercsv.cellprocessor.ift.CellProcessor;
import com.github.mygreen.supercsv.annotation.constraint.CsvEquals;
import com.github.mygreen.supercsv.annotation.constraint.CsvRequire;
import com.github.mygreen.supercsv.annotation.constraint.CsvUnique;
import com.github.mygreen.supercsv.annotation.constraint.CsvUniqueHashCode;
import com.github.mygreen.supercsv.annotation.conversion.CsvDefaultValue;
import com.github.mygreen.supercsv.annotation.conversion.CsvFullChar;
import com.github.mygreen.supercsv.annotation.conversion.CsvHalfChar;
import com.github.mygreen.supercsv.annotation.conversion.CsvLeftPad;
import com.github.mygreen.supercsv.annotation.conversion.CsvLower;
import com.github.mygreen.supercsv.annotation.conversion.CsvMultiPad;
import com.github.mygreen.supercsv.annotation.conversion.CsvNullConvert;
import com.github.mygreen.supercsv.annotation.conversion.CsvOneSideTrim;
import com.github.mygreen.supercsv.annotation.conversion.CsvRegexReplace;
import com.github.mygreen.supercsv.annotation.conversion.CsvRightPad;
import com.github.mygreen.supercsv.annotation.conversion.CsvTrim;
import com.github.mygreen.supercsv.annotation.conversion.CsvUpper;
import com.github.mygreen.supercsv.annotation.conversion.CsvWordReplace;
import com.github.mygreen.supercsv.annotation.format.CsvFormat;
import com.github.mygreen.supercsv.cellprocessor.ConstraintProcessorFactory;
import com.github.mygreen.supercsv.cellprocessor.ConstraintProcessorHandler;
import com.github.mygreen.supercsv.cellprocessor.ConversionProcessorFactory;
import com.github.mygreen.supercsv.cellprocessor.ConversionProcessorHandler;
import com.github.mygreen.supercsv.cellprocessor.ProcessorFactory;
import com.github.mygreen.supercsv.cellprocessor.constraint.EqualsFactory;
import com.github.mygreen.supercsv.cellprocessor.constraint.RequireFactory;
import com.github.mygreen.supercsv.cellprocessor.constraint.UniqueFactory;
import com.github.mygreen.supercsv.cellprocessor.constraint.UniqueHashCodeFactory;
import com.github.mygreen.supercsv.cellprocessor.conversion.DefaultValueFactory;
import com.github.mygreen.supercsv.cellprocessor.conversion.FullCharFactory;
import com.github.mygreen.supercsv.cellprocessor.conversion.HalfCharFactory;
import com.github.mygreen.supercsv.cellprocessor.conversion.LeftPadFactory;
import com.github.mygreen.supercsv.cellprocessor.conversion.LowerFactory;
import com.github.mygreen.supercsv.cellprocessor.conversion.MultiPadFactory;
import com.github.mygreen.supercsv.cellprocessor.conversion.NullConvertFactory;
import com.github.mygreen.supercsv.cellprocessor.conversion.OneSideTrimFactory;
import com.github.mygreen.supercsv.cellprocessor.conversion.RegexReplaceFactory;
import com.github.mygreen.supercsv.cellprocessor.conversion.RightPadFactory;
import com.github.mygreen.supercsv.cellprocessor.conversion.TrimFactory;
import com.github.mygreen.supercsv.cellprocessor.conversion.UpperFactory;
import com.github.mygreen.supercsv.cellprocessor.conversion.WordReplaceFactory;
import com.github.mygreen.supercsv.cellprocessor.format.ParseProcessorFactory;
import com.github.mygreen.supercsv.cellprocessor.format.PrintProcessorFactory;
import com.github.mygreen.supercsv.cellprocessor.format.TextFormatter;
/**
* アノテーションによる{@link CellProcessor}を組み立てるベースとなるクラス。
* <p>共通の{@link CellProcessor}などを追加する処理を定義します。
*
* @param <T> 処理対象のクラスタイプ。
* @version 2.0
* @author T.TSUCHIE
*
*/
public abstract class AbstractProcessorBuilder<T> implements ProcessorBuilder<T> {
/**
* 読み込み時の変換用のCellProcessorを作成する。
*/
protected List<ProcessorFactory> readingFactory = new ArrayList<>();
/**
* 書き込み時の変換用のCellProcessorを作成する。
*/
protected List<ProcessorFactory> writingFactory = new ArrayList<>();
/**
* 変換のCellProcessorを作成する
*/
protected ConversionProcessorHandler conversionHandler = new ConversionProcessorHandler();
/**
* 制約のCellProcessorを作成する
*/
protected ConstraintProcessorHandler constraintHandler = new ConstraintProcessorHandler();
/**
* デフォルトコンストラクタ。
* <p>{@link #init()}メソッドが呼ばれる。
*/
public AbstractProcessorBuilder() {
init();
}
/**
* デフォルトの{@link ProcessorFactory}などの登録を行い、初期化を行う。
*
*/
protected void init() {
// 読み込み用の登録
registerForReading(conversionHandler);
registerForReading(new ParseProcessorFactory<>());
registerForReading(constraintHandler);
// 書き込み用の登録
registerForWriting(constraintHandler);
registerForWriting(new PrintProcessorFactory<>());
registerForWriting(conversionHandler);
// 変換用の登録
registerForConversion(CsvNullConvert.class, new NullConvertFactory());
registerForConversion(CsvDefaultValue.class, new DefaultValueFactory());
registerForConversion(CsvTrim.class, new TrimFactory());
registerForConversion(CsvUpper.class, new UpperFactory());
registerForConversion(CsvLower.class, new LowerFactory());
registerForConversion(CsvRegexReplace.class, new RegexReplaceFactory());
registerForConversion(CsvWordReplace.class, new WordReplaceFactory());
registerForConversion(CsvFullChar.class, new FullCharFactory());
registerForConversion(CsvHalfChar.class, new HalfCharFactory());
registerForConversion(CsvLeftPad.class, new LeftPadFactory());
registerForConversion(CsvRightPad.class, new RightPadFactory());
registerForConversion(CsvMultiPad.class, new MultiPadFactory());
registerForConversion(CsvOneSideTrim.class, new OneSideTrimFactory());
// 制約用の登録
registerForConstraint(CsvRequire.class, new RequireFactory());
registerForConstraint(CsvUnique.class, new UniqueFactory<>());
registerForConstraint(CsvUniqueHashCode.class, new UniqueHashCodeFactory<>());
registerForConstraint(CsvEquals.class, new EqualsFactory<>());
}
@Override
public Optional<CellProcessor> buildForReading(final Class<T> type, final FieldAccessor field,
final Configuration config, final Class<?>[] groups) {
// 登録時とは逆順に処理する
final List<ProcessorFactory> factories = new ArrayList<>(readingFactory);
Collections.reverse(factories);
final TextFormatter<T> formatter = getFormatter(field, config);
Optional<CellProcessor> processor = Optional.empty();
for(ProcessorFactory factory : factories) {
processor = factory.create(processor, field, formatter, config, BuildCase.Read, groups);
}
return processor;
}
@Override
public Optional<CellProcessor> buildForWriting(final Class<T> type, final FieldAccessor field,
final Configuration config, final Class<?>[] groups) {
// 登録時とは逆順に処理する
final List<ProcessorFactory> factories = new ArrayList<>(writingFactory);
Collections.reverse(factories);
final TextFormatter<T> formatter = getFormatter(field, config);
Optional<CellProcessor> processor = Optional.empty();
for(ProcessorFactory factory : factories) {
//制約のProcessorの実行有無の判定
if(config.isSkipValidationOnWrite()
&& factory instanceof ConstraintProcessorHandler) {
continue;
}
processor = factory.create(processor, field, formatter, config, BuildCase.Write, groups);
}
return processor;
}
/**
* 読み込み用のCellProcessorを作成するクラスを登録する。
* <p>実行時は、登録された順に処理される。
* @param factory {@link ProcessorFactory}の実装クラス。
*/
public void registerForReading(final ProcessorFactory factory) {
this.readingFactory.add(factory);
}
/**
* 書き込み用のCellProcessorを作成するクラスを登録する。
* <p>実行時は、登録された順に処理される。
* @param factory {@link ProcessorFactory}の実装クラス。
*/
public void registerForWriting(final ProcessorFactory factory) {
this.writingFactory.add(factory);
}
/**
* 変換のCellProcessorを作成するクラスを登録する。読み込み時と書き込み時は共通です。
*
* @param <A> アノテーションのクラス
* @param anno 関連づけるアノテーション
* @param factory アノテーションを処理する{@link ConversionProcessorFactory}の実装。
*/
public <A extends Annotation> void registerForConversion(final Class<A> anno, final ConversionProcessorFactory<A> factory) {
this.conversionHandler.register(anno, factory);
}
/**
* 制約のCellProcessorを作成するクラスを登録する。読み込み時と書き込み時は共通です。
*
* @param <A> アノテーションのクラス
* @param anno 関連づけるアノテーション
* @param factory アノテーションを処理する{@link ConstraintProcessorFactory}の実装。
*/
public <A extends Annotation> void registerForConstraint(final Class<A> anno, final ConstraintProcessorFactory<A> factory) {
this.constraintHandler.register(anno, factory);
}
/**
* 文字列とオブジェクトを相互変換するフォーマッタを取得します。
* <p>アノテーション{@link CsvFormat}が指定されている場合は、そちらを優先します。</p>
* @param field フィールド情報
* @param config システム設定
* @return フォーマッタを取得します。
*/
@SuppressWarnings("unchecked")
public TextFormatter<T> getFormatter(final FieldAccessor field, final Configuration config) {
if(field.hasAnnotation(CsvFormat.class)) {
CsvFormat formatAnno = field.getAnnotation(CsvFormat.class).get();
final TextFormatter<T> formatter = (TextFormatter<T>) config.getBeanFactory().create(formatAnno.formatter());
if(!formatAnno.message().isEmpty()) {
formatter.setValidationMessage(formatAnno.message());
}
return formatter;
} else {
return getDefaultFormatter(field, config);
}
}
/**
* 文字列とオブジェクトを相互変換する標準のフォーマッタを取得します。
* <p>書式が設定されている場合は、書式に沿って処理を行います。</p>
* @param field フィールド情報
* @param config システム設定
* @return 標準のフォーマッタを取得します。
*/
protected abstract TextFormatter<T> getDefaultFormatter(FieldAccessor field, Configuration config);
/**
* 登録している変換用のアノテーションとそのファクトリクラスの情報を取得します。
* @return アノテーションと対応する{@link ConversionProcessorFactory}のマップ。
*/
public Set<Map.Entry<Class<? extends Annotation>, ConversionProcessorFactory<?>>> getEntrySetForConversion() {
return conversionHandler.getEntrySet();
}
/**
* 登録している検証用のアノテーションとそのファクトリクラスの情報を取得します。
* @return アノテーションと対応する{@link ConstraintProcessorFactory}のマップ。
*/
public Set<Map.Entry<Class<? extends Annotation>, ConstraintProcessorFactory<?>>> getEntrySetForConsraint() {
return constraintHandler.getEntrySet();
}
}