CellConverterFactorySupport.java
package com.gh.mygreen.xlsmapper.cellconverter;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Optional;
import com.gh.mygreen.xlsmapper.AnnotationInvalidException;
import com.gh.mygreen.xlsmapper.Configuration;
import com.gh.mygreen.xlsmapper.annotation.XlsCellOption;
import com.gh.mygreen.xlsmapper.annotation.XlsDefaultValue;
import com.gh.mygreen.xlsmapper.annotation.XlsFormula;
import com.gh.mygreen.xlsmapper.annotation.XlsTrim;
import com.gh.mygreen.xlsmapper.expression.ExpressionEvaluationException;
import com.gh.mygreen.xlsmapper.fieldaccessor.FieldAccessor;
import com.gh.mygreen.xlsmapper.localization.MessageBuilder;
import com.gh.mygreen.xlsmapper.textformatter.TextFormatter;
import com.gh.mygreen.xlsmapper.textformatter.TextParseException;
import com.gh.mygreen.xlsmapper.util.Utils;
/**
* {@link CellConverter}を作成するための抽象クラス。
*
* @since 2.0
* @author T.TSUCHIE
*
*/
public abstract class CellConverterFactorySupport<T> {
/**
* 引数で指定したCellConverterに対して、トリムなどの共通の設定を行う。
* @param cellConverter 設定を行うCellConverter
* @param field フィールド情報
* @param config システム設定情報
*/
protected void setupCellConverter(final BaseCellConverter<T> cellConverter, final FieldAccessor field, final Configuration config) {
final TextFormatter<T> textFormatter = createTextFormatter(field, config);
cellConverter.setTextFormatter(textFormatter);
// トリムの設定
final Optional<XlsTrim> trimAnno = field.getAnnotation(XlsTrim.class);
final boolean trimmed = trimAnno.map(anno -> true).orElse(false);
cellConverter.setTrimmed(trimmed);
// 初期値の設定
final Optional<XlsDefaultValue> defaultValueAnno = field.getAnnotation(XlsDefaultValue.class);
defaultValueAnno.ifPresent(anno -> {
String text = Utils.trim(anno.value(), trimmed);
try {
T defaultValue = textFormatter.parse(text);
cellConverter.setDefaultValue(defaultValue, anno.cases());
} catch(TextParseException e) {
throw new AnnotationInvalidException(anno, MessageBuilder.create("anno.XlsDefaultValue.failParse")
.var("property", field.getNameWithClass())
.var("defaultValue", text)
.varWithClass("type", field.getType())
.format(), e);
}
});
// セルの書式の設定
final Optional<XlsCellOption> cellOptionAnno = field.getAnnotation(XlsCellOption.class);
cellOptionAnno.ifPresent(anno -> {
cellConverter.setShrinktToFit(anno.shrinkToFit());
cellConverter.setWrapText(anno.wrapText());
cellConverter.setIndent(anno.indent());
cellConverter.setHorizontalAlignment(anno.horizontalAlign().poiAlignType());
cellConverter.setVerticalAlignment(anno.verticalAlign().poiAlignType());
});
// 数式の設定
final Optional<XlsFormula> formulaAnno = field.getAnnotation(XlsFormula.class);
formulaAnno.ifPresent(anno -> {
CellFormulaHandler formulaHandler = createCellFormulaHandler(anno, field, config);
cellConverter.setFormulaHandler(formulaHandler);
});
// 各個別の設定
setupCustom(cellConverter, field, config);
}
/**
* 各個別に、Converterの設定を行う。
* @param cellConverter 組み立てるCellConverterのインスタンス
* @param field フィールド情報
* @param config システム情報
*/
protected abstract void setupCustom(BaseCellConverter<T> cellConverter, FieldAccessor field, Configuration config);
/**
* {@link TextFormatter}のインスタンスを作成する。
* @param field フィールド情報
* @param config システム情報
* @return {@link TextFormatter}のインスタンス
*/
protected abstract TextFormatter<T> createTextFormatter(FieldAccessor field, Configuration config);
/**
* 数式を処理する{@link CellFormulaHandler}を作成する。
* @param formulaAnno 数式のアノテーション
* @param field フィールド情報
* @param config システム情報
* @return {@link CellFormulaHandler}のインスタンス
*/
protected CellFormulaHandler createCellFormulaHandler(final XlsFormula formulaAnno, final FieldAccessor field, final Configuration config) {
if(!formulaAnno.value().isEmpty()) {
final String formulaExpression = formulaAnno.value();
try {
// EL式として正しいか検証する
config.getFormulaFormatter().interpolate(formulaExpression, Collections.emptyMap());
} catch(ExpressionEvaluationException e) {
throw new AnnotationInvalidException(formulaAnno, MessageBuilder.create("anno.attr.invalidEL")
.var("property", field.getNameWithClass())
.varWithAnno("anno", XlsFormula.class)
.var("attrName", "value")
.var("attrValue", formulaExpression)
.format());
}
CellFormulaHandler handler = new CellFormulaHandler(formulaExpression);
handler.setPrimaryFormula(formulaAnno.primary());
return handler;
} else if(!formulaAnno.methodName().isEmpty()) {
// 戻り値が文字列の数式を返すメソッドを探す
final Class<?> targetClass = field.getDeclaringClass();
Method method = null;
for(Method m : targetClass.getDeclaredMethods()) {
if(m.getName().equals(formulaAnno.methodName())
&& m.getReturnType().equals(String.class)) {
method = m;
break;
}
}
if(method == null) {
throw new AnnotationInvalidException(formulaAnno, MessageBuilder.create("anno.attr.notFoundMethod")
.var("property", field.getNameWithClass())
.varWithAnno("anno", XlsFormula.class)
.var("attrName", "methodName")
.var("attrValue", formulaAnno.methodName())
.varWithClass("definedClass", targetClass)
.format());
}
method.setAccessible(true);
CellFormulaHandler handler = new CellFormulaHandler(method);
handler.setPrimaryFormula(formulaAnno.primary());
return handler;
} else {
throw new AnnotationInvalidException(formulaAnno, MessageBuilder.create("anno.attr.required.any")
.var("property", field.getNameWithClass())
.varWithAnno("anno", XlsFormula.class)
.varWithArrays("attrNames", "value", "methodName")
.format());
}
}
}