package com.github.mygreen.supercsv.builder.joda; import java.util.Locale; import java.util.Optional; import java.util.TimeZone; import org.joda.time.Chronology; import org.joda.time.DateTimeZone; import org.joda.time.ReadablePartial; import org.joda.time.chrono.ISOChronology; import org.joda.time.chrono.LenientChronology; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import com.github.mygreen.supercsv.annotation.constraint.CsvDateTimeRange; import com.github.mygreen.supercsv.annotation.constraint.CsvDateTimeMin; import com.github.mygreen.supercsv.annotation.constraint.CsvDateTimeMax; import com.github.mygreen.supercsv.annotation.format.CsvDateTimeFormat; import com.github.mygreen.supercsv.builder.AbstractProcessorBuilder; import com.github.mygreen.supercsv.builder.Configuration; import com.github.mygreen.supercsv.builder.FieldAccessor; import com.github.mygreen.supercsv.cellprocessor.constraint.DateTimeRangeFactory; import com.github.mygreen.supercsv.cellprocessor.constraint.DateTimeMinFactory; import com.github.mygreen.supercsv.cellprocessor.constraint.DateTimeMaxFactory; import com.github.mygreen.supercsv.cellprocessor.format.JodaFormatWrapper; import com.github.mygreen.supercsv.cellprocessor.format.TextFormatter; import com.github.mygreen.supercsv.util.Utils; /** * Joda-Time の{@link ReadablePartial}のテンプレートクラス。 * <p>基本的に、{@link ReadablePartial}のサブクラスのビルダは、このクラスを継承して作成する。</p> * * @version 2.0 * @since 1.2 * @author T.TSUCHIE * */ public abstract class AbstractJodaProcessorBuilder<T> extends AbstractProcessorBuilder<T> { public AbstractJodaProcessorBuilder() { super(); } @Override protected void init() { super.init(); // 制約のアノテーションの追加 registerForConstraint(CsvDateTimeRange.class, new DateTimeRangeFactory<>()); registerForConstraint(CsvDateTimeMin.class, new DateTimeMinFactory<>()); registerForConstraint(CsvDateTimeMax.class, new DateTimeMaxFactory<>()); } /** * 変換規則から、{@link DateTimeFormatter}のインスタンスを作成する。 * <p>アノテーション{@link CsvDateTimeFormat}が付与されていない場合は、各種タイプごとの標準の書式で作成する。</p> * @param field フィールド情報 * @param config システム設定 * @return {@link DateTimeFormatter}のインスタンス。 */ protected DateTimeFormatter createFormatter(final FieldAccessor field, final Configuration config) { final Optional<CsvDateTimeFormat> formatAnno = field.getAnnotation(CsvDateTimeFormat.class); if(!formatAnno.isPresent()) { return DateTimeFormat.forPattern(getDefaultPattern()); } String pattern = formatAnno.get().pattern(); if(pattern.isEmpty()) { pattern = getDefaultPattern(); } final Locale locale = Utils.getLocale(formatAnno.get().locale()); final DateTimeZone zone = formatAnno.get().timezone().isEmpty() ? DateTimeZone.getDefault() : DateTimeZone.forTimeZone(TimeZone.getTimeZone(formatAnno.get().timezone())); final DateTimeFormatter formatter = DateTimeFormat.forPattern(pattern) .withLocale(locale) .withZone(zone); final boolean lenient = formatAnno.get().lenient(); if(lenient) { Chronology chronology = LenientChronology.getInstance(ISOChronology.getInstance()); return formatter.withChronology(chronology); } else { return formatter; } } @SuppressWarnings("unchecked") @Override protected TextFormatter<T> getDefaultFormatter(final FieldAccessor field, final Configuration config) { final Optional<CsvDateTimeFormat> formatAnno = field.getAnnotation(CsvDateTimeFormat.class); final String pattern = getPattern(field); final DateTimeFormatter formatter = createFormatter(field, config); final JodaFormatWrapper<T> wrapper = new JodaFormatWrapper<>(formatter, (Class<T>)field.getType()); wrapper.setPattern(pattern); formatAnno.ifPresent(a -> wrapper.setValidationMessage(a.message())); return wrapper; } /** * アノテーション{@link CsvDateTimeFormat}が付与されている場合は、パターンを取得する。 * <p>ただし、アノテーションが付与されていない場合は、{@link #getDefaultPattern()}の値を返す。</p> * <p>{@link DateTimeFormatter}のインスタンスからは、元となったパターンは直接取得できないため、 * 別途取得して利用するために使用する。</p> * @param field フィールド情報。 * @return 日時の書式パターン。 */ protected String getPattern(final FieldAccessor field) { return field.getAnnotation(CsvDateTimeFormat.class) .map(a -> a.pattern()) .filter(p -> !p.isEmpty()) .orElse(getDefaultPattern()); } /** * 変換規則用のアノテーションが定義されていないときの標準の書式を取得する。 * * @return {@link DateTimeFormatter}で解析可能な日時の書式。 */ protected abstract String getDefaultPattern(); }