TemporalFormatWrapper.java

package com.github.mygreen.supercsv.cellprocessor.format;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDate;
import java.time.chrono.JapaneseDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.TemporalAccessor;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import com.github.mygreen.supercsv.util.Utils;

/**
 * Date and Time APIの{@link DateTimeFormatter}をラップしたクラス。
 *
 * @version 2.1
 * @since 2.0
 * @author T.TSUCHIE
 *
 */
public class TemporalFormatWrapper<T extends TemporalAccessor> extends AbstractTextFormatter<T> {
    
    private final DateTimeFormatter formatter;
    
    private final Class<T> type;
    
    private final Method parseMethod;
    
    private String pattern;
    
    /**
     * 
     * @param formatter ラップする{@link DateTimeFormatter}を指定します。
     * @param type {@link TemporalAccessor}の実装クラスを指定します。
     * @throws NullPointerException {@literal if formatter or type is null.}
     * @throws IllegalArgumentException {@literal type is not support class type.}
     */
    public TemporalFormatWrapper(final DateTimeFormatter formatter, final Class<T> type) {
        Objects.requireNonNull(formatter);
        Objects.requireNonNull(type);
        
        this.formatter = formatter;
        this.type = type;
        
        
        try {
            this.parseMethod = type.getMethod("parse", CharSequence.class, DateTimeFormatter.class);
            
        } catch (NoSuchMethodException | SecurityException e) {
            throw new IllegalArgumentException(String.format("Cannot suuport type : %s.", type.getName()));
        }
        
    }
    
    /**
     * {@inheritDoc}
     * 
     * サポートしていないクラスタイプの場合、例外{@link TextParseException}がスローされます。
     */
    @SuppressWarnings("unchecked")
    @Override
    public T parse(final String text) {
        
        try {
            return (T) parseMethod.invoke(type, text, formatter);
            
        } catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            throw new TextParseException(text, type, "Cannot suuport type.");
            
        } catch(DateTimeParseException e) {
            throw new TextParseException(text, type, e);
        }
        
    }
    
    @Override
    public String print(final T object) {
        
        if(pattern.contains("G") && formatter.getLocale().getLanguage().equals("ja")) {
            if(LocalDate.class.isAssignableFrom(type)) {
                JapaneseDate date = JapaneseDate.from((LocalDate)object);
                return formatter.format(date);
            }
        }
        
        
        return formatter.format(object);
    }
    
    @Override
    public Optional<String> getPattern() {
        if(Utils.isEmpty(pattern)) {
            return Optional.empty();
        } else {
            return Optional.of(pattern);
        }
    }
    
    /**
     * パースする際のエラーメッセージ中に利用する書式を指定します。
     * @param pattern コンストラクタで指定した{@link DateTimeFormatter}に対応する書式を指定します。
     */
    public void setPattern(String pattern) {
        this.pattern = pattern;
    }
    
    @Override
    public Map<String, Object> getMessageVariables() {
        final Map<String, Object> vars = new HashMap<>();
        getPattern().ifPresent(p -> vars.put("pattern", p));
        
        return vars;
    }
    
}