CellFormulaHandler.java
- package com.gh.mygreen.xlsmapper.cellconverter;
- import java.awt.Point;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Optional;
- import org.apache.poi.ss.formula.FormulaParseException;
- import org.apache.poi.ss.usermodel.Cell;
- import org.apache.poi.ss.usermodel.Sheet;
- import org.apache.poi.ss.util.CellReference;
- import com.gh.mygreen.xlsmapper.Configuration;
- import com.gh.mygreen.xlsmapper.XlsMapperException;
- import com.gh.mygreen.xlsmapper.fieldaccessor.FieldAccessor;
- import com.gh.mygreen.xlsmapper.localization.MessageBuilder;
- import com.gh.mygreen.xlsmapper.util.ArgUtils;
- import com.gh.mygreen.xlsmapper.util.CellPosition;
- import com.gh.mygreen.xlsmapper.util.Utils;
- /**
- * セルの数式を処理する
- *
- * @since 2.0
- * @author T.TSUCHIE
- *
- */
- public class CellFormulaHandler {
-
- /**
- * 数式を直接指定している場合
- */
- private Optional<String> formula = Optional.empty();
-
- /**
- * 数式を取得するメソッドを指定している場合
- */
- private Optional<Method> method = Optional.empty();
-
- /**
- * セルの値が設定済みの時に、数式の設定を優先するかどうか。
- */
- private boolean primaryFormula;
-
- /**
- * 数式を直接指定する場合
- * @param formula 数式。EL式で評価可能な形式。
- * @throws IllegalArgumentException {@literal formula == null or empty.}
- */
- public CellFormulaHandler(final String formula) {
- ArgUtils.notEmpty(formula, "formula");
-
- this.formula = Optional.of(formula);
- }
-
- /**
- * 数式を取得するメソッドを指定する場合
- * @param method 数式を取得するためのメソッド
- * @throws IllegalArgumentException {@literal method == null.}
- */
- public CellFormulaHandler(final Method method) {
- ArgUtils.notNull(method, "method");
-
- this.method = Optional.of(method);
-
- }
-
- /**
- * セルに数式を設定する
- * @param field フィールド情報
- * @param config システム情報
- * @param cell セル情報
- * @param targetBean 処理対象のフィールドが定義されているクラスのインスタンス。
- * @throws ConversionException 数式の解析に失敗した場合。
- */
- public void handleFormula(final FieldAccessor field, final Configuration config, final Cell cell, final Object targetBean) {
-
- ArgUtils.notNull(field, "field");
- ArgUtils.notNull(config, "config");
- ArgUtils.notNull(cell, "cell");
-
- final String evaluatedFormula = createFormulaValue(config, cell, targetBean);
- if(Utils.isEmpty(evaluatedFormula)) {
- cell.setBlank();
- return;
- }
-
- try {
- cell.setCellFormula(evaluatedFormula);
-
- } catch(FormulaParseException e) {
- // 数式の解析に失敗した場合
- String message = MessageBuilder.create("cell.failParseFormula")
- .var("property", field.getNameWithClass())
- .var("cellAddress", CellPosition.of(cell).toString())
- .var("formula", evaluatedFormula)
- .format();
-
- throw new ConversionException(message, e, field.getType());
- }
-
- }
-
- /**
- * Excelの式を組み立てる。
- * @param config システム情報設定
- * @param cell セル情報
- * @param targetBean 処理対象のフィールドが定義されているクラスのインスタンス。
- * @return 組み立てた数式
- */
- public String createFormulaValue(final Configuration config, final Cell cell, final Object targetBean) {
-
- if(formula.isPresent()) {
- final Map<String, Object> vars = new HashMap<>();
- vars.put("rowIndex", cell.getRowIndex());
- vars.put("columnIndex", cell.getColumnIndex());
- vars.put("rowNumber", cell.getRowIndex()+1);
- vars.put("columnNumber", cell.getColumnIndex()+1);
- vars.put("columnAlpha", CellReference.convertNumToColString(cell.getColumnIndex()));
- vars.put("address", CellPosition.of(cell).formatAsString());
- vars.put("targetBean", targetBean);
- vars.put("cell", cell);
-
- return config.getFormulaFormatter().interpolate(formula.get(), vars);
-
- } else if(method.isPresent()) {
-
- // メソッドの引数の組み立て
- final Class<?>[] paramTypes = method.get().getParameterTypes();
- final Object[] paramValues = new Object[paramTypes.length];
-
- for(int i=0; i < paramTypes.length; i++) {
- if(Cell.class.isAssignableFrom(paramTypes[i])) {
- paramValues[i] = cell;
-
- } else if(CellPosition.class.isAssignableFrom(paramTypes[i])) {
- paramValues[i] = CellPosition.of(cell);
-
- } else if(Point.class.isAssignableFrom(paramTypes[i])) {
- paramValues[i] = CellPosition.of(cell).toPoint();
-
- } else if(org.apache.poi.ss.util.CellAddress.class.isAssignableFrom(paramTypes[i])) {
- paramValues[i] = CellPosition.of(cell).toCellAddress();
-
- } else if(Sheet.class.isAssignableFrom(paramTypes[i])) {
- paramValues[i] = cell.getSheet();
-
- } else if(Configuration.class.isAssignableFrom(paramTypes[i])) {
- paramValues[i] = config;
-
- } else {
- paramValues[i] = null;
- }
- }
-
- try {
- return (String) method.get().invoke(targetBean, paramValues);
-
- } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
- final Class<?> targetClass = targetBean.getClass();
- final Throwable t = e.getCause() == null ? e : e.getCause();
- throw new XlsMapperException(
- String.format("Fail execute method '%s#%s'.", targetClass.getName(), method.get().getName()),
- t);
- }
-
- } else {
- // 数式や対応するメソッドがない場合
- throw new IllegalStateException("not found for formula or method.");
- }
-
- }
-
- /**
- * セルの値が設定済みの時に、数式の設定を優先するかどうか。
- */
- public boolean isPrimaryFormula() {
- return primaryFormula;
- }
-
- /**
- * セルの値が設定済みの時に、数式の設定を優先するかどうか。
- * @param primaryFormula 数式の設定を優先するかどうか
- */
- public void setPrimaryFormula(boolean primaryFormula) {
- this.primaryFormula = primaryFormula;
- }
-
- }