CellField.java

  1. package com.gh.mygreen.xlsmapper.validation.fieldvalidation;

  2. import java.util.ArrayList;
  3. import java.util.Arrays;
  4. import java.util.Collections;
  5. import java.util.List;
  6. import java.util.Map;
  7. import java.util.Optional;

  8. import com.gh.mygreen.xlsmapper.fieldaccessor.LabelGetterFactory;
  9. import com.gh.mygreen.xlsmapper.fieldaccessor.PositionGetterFactory;
  10. import com.gh.mygreen.xlsmapper.util.ArgUtils;
  11. import com.gh.mygreen.xlsmapper.util.CellPosition;
  12. import com.gh.mygreen.xlsmapper.validation.FieldError;
  13. import com.gh.mygreen.xlsmapper.validation.FieldErrorBuilder;
  14. import com.gh.mygreen.xlsmapper.validation.SheetBindingErrors;


  15. /**
  16.  * 1つの項目(フィールド)に対する入力値チェックをするためのクラス。
  17.  * <p>型変換などにおけるバインドエラーなどはシートの読み込み時に行われます。
  18.  * <p>必須エラーのメッセージキーは、「fieldError.required」。
  19.  *
  20.  * @version 0.5
  21.  * @author T.TSUCHIE
  22.  * @param <T> チェック対象の値のタイプ
  23.  *
  24.  */
  25. public class CellField<T> {

  26.     private static final PositionGetterFactory positionGetterFactory = new PositionGetterFactory();
  27.     private static final LabelGetterFactory labelGetterFactory = new LabelGetterFactory();

  28.     private final SheetBindingErrors<?> errors;

  29.     /**
  30.      * フィールドの名称
  31.      */
  32.     private final String fieldName;

  33.     /**
  34.      * フィールドが定義されているBeanクラスのインスタンス
  35.      */
  36.     private Object beanObj;

  37.     /**
  38.      * フィールドの値
  39.      */
  40.     private T fieldValue;

  41.     /**
  42.      * フィールドのJavaBean上のパス
  43.      */
  44.     private String fieldPath;

  45.     /**
  46.      * セルの位置情報。
  47.      * Beanに定義されたプロパティ情報から取得する。
  48.      * 定義されていない場合は、nullが設定される。
  49.      */
  50.     private CellPosition position;

  51.     /**
  52.      * セルのラベル情報
  53.      * Beanに定義されたプロパティ情報から取得する。
  54.      * 定義されていない場合は、nullが設定される。
  55.      */
  56.     private String label;

  57.     /**
  58.      * 必須かどうか
  59.      */
  60.     private boolean required;

  61.     private List<FieldValidator<T>> validators;

  62.     private FieldFormatter<T> formatter;

  63.     private Class<T> fieldType;

  64.     /**
  65.      * 指定されたフィールドの名称に対応するオブジェクトを構築します。
  66.      * @param fieldName フィールドの名称。現在のBeanに対するフィールドの相対パスを指定します。
  67.      * @param errors エラー情報
  68.      */
  69.     public CellField(final String fieldName, final SheetBindingErrors<?> errors) {

  70.         ArgUtils.notEmpty(fieldName, "fieldName");
  71.         ArgUtils.notNull(errors, "errors");

  72.         this.fieldName = fieldName;
  73.         this.errors = errors;

  74.         init();
  75.     }

  76.     @SuppressWarnings("unchecked")
  77.     private void init() {

  78.         this.beanObj = errors.getValue();
  79.         this.fieldValue = (T)errors.getFieldValue(fieldName);
  80.         this.fieldType = (Class<T>)errors.getFieldType(fieldName);
  81.         this.fieldPath = errors.buildFieldPath(fieldName);

  82.         Optional<CellPosition> position = positionGetterFactory.create(beanObj.getClass(), fieldName)
  83.                 .map(getter -> getter.get(beanObj)).orElse(Optional.empty());
  84.         position.ifPresent(p -> setPosition(p));

  85.         Optional<String> label = labelGetterFactory.create(beanObj.getClass(), fieldName)
  86.                 .map(getter -> getter.get(beanObj)).orElse(Optional.empty());
  87.         label.ifPresent(l -> setLabel(l));

  88.         this.required = false;
  89.         this.validators = new ArrayList<>();

  90.         this.formatter = errors.findFieldFormatter(fieldName, fieldType);
  91.     }

  92.     /**
  93.      * 値が必須かの設定を行う。
  94.      * @param required 必須チェックを行いたい場合、「true」を設定する。
  95.      * @return 自身のインスタンス。メソッドチェーンで記述する。
  96.      */
  97.     public CellField<T> setRequired(final boolean required) {
  98.         this.required = required;
  99.         return this;
  100.     }

  101.     /**
  102.      * 値が必須かチェックを行うかどうか。
  103.      * @return true: 必須入力チェックを行う。
  104.      *               初期値は、非必須(オプション)です。
  105.      */
  106.     public boolean isRequired() {
  107.         return required;
  108.     }

  109.     /**
  110.      * {@link FieldValidator} を追加する。
  111.      * @param validator validatorのインスタンス。
  112.      * @return 自身のインスタンス。
  113.      * @throws NullPointerException validator is null.
  114.      */
  115.     public CellField<T> add(final FieldValidator<T> validator) {
  116.         ArgUtils.notNull(validator, "validator");
  117.         this.validators.add(validator);

  118.         return this;
  119.     }

  120.     /**
  121.      * 複数の{@link FieldValidator} を追加する。
  122.      * @param validators 複数のvalidatorのインスタンス。
  123.      * @return 自身のインスタンス。
  124.      * @throws NullPointerException validator is null.
  125.      */
  126.     public CellField<T> add(final List<FieldValidator<T>> validators) {

  127.         if(validators.isEmpty()) {
  128.             return this;
  129.         }

  130.         for(FieldValidator<T> validator : validators) {
  131.             add(validator);
  132.         }
  133.         return this;
  134.     }

  135.     /**
  136.      * 現在の{@link FieldValidator}を取得する。
  137.      * @return 現在設定されている{@link FieldValidator}。
  138.      */
  139.     public List<FieldValidator<T>> getValidators() {
  140.         return validators;
  141.     }

  142.     /**
  143.      * グループなどのヒントを指定して、入力値の検証を行う。
  144.      * <p>判定結果は、{@link #hasErrors()}で確認します。</p>
  145.      * <p>型変換エラーなどが既に存在するときには、処理は終了します。</p>
  146.      *
  147.      * @param groups 検証するときのヒントとなるグループ。
  148.      * @return 自身のインスタンス。
  149.      */
  150.     public CellField<T> validate(final Class<?>... groups) {

  151.         // 既に型変換エラーなどがある場合、値が設定されていないため処理を終了します。
  152.         if(hasErrors()) {
  153.             return this;
  154.         }

  155.         // 必須チェック
  156.         if(!validateForRequired()) {
  157.             return this;
  158.         }

  159.         final List<Class<?>> hints = Arrays.asList(groups);

  160.         if(getValidators() != null && !getValidators().isEmpty()) {
  161.             for(FieldValidator<T> validator : getValidators()) {
  162.                 if(!validator.validate(this, hints)) {
  163.                     return this;
  164.                 }
  165.             }
  166.         }

  167.         return this;

  168.     }

  169.     /**
  170.      * 必須エラーのメッセージキーを取得する。
  171.      * <p>キー名は、「fieldError.required」。
  172.      * @return
  173.      */
  174.     protected String getMessageKeyRequired() {
  175.         return "cellFieldError.required";
  176.     }

  177.     /**
  178.      * 必須チェックを行う。
  179.      * @return trueの場合、必須エラーでない。
  180.      */
  181.     protected boolean validateForRequired() {

  182.         if(isRequired() && isInputEmpty()) {
  183.             errors.createFieldError(fieldName, getMessageKeyRequired())
  184.                 .address(getPosition())
  185.                 .label(getLabel())
  186.                 .variables("validatedValue", getValue())
  187.                 .buildAndAddError();
  188.             return false;
  189.         }

  190.         return true;

  191.     }

  192.     /**
  193.      * エラーを追加する。
  194.      * @param errorCode エラーコード
  195.      */
  196.     public void rejectValue(final String errorCode) {
  197.         rejectValue(errorCode, Collections.emptyMap());
  198.     }

  199.     /**
  200.      * エラーを追加する
  201.      * @param errorCode エラコード
  202.      * @param variables エラーメッセージ中の変数
  203.      */
  204.     public void rejectValue(final String errorCode, final Map<String, Object> variables) {

  205.         final String codes[] = errors.generateMessageCodes(errorCode, fieldPath, fieldType);

  206.         final FieldError error = new FieldErrorBuilder(errors.getObjectName(), fieldPath, codes)
  207.             .sheetName(errors.getSheetName())
  208.             .rejectedValue(fieldValue)
  209.             .variables(variables)
  210.             .address(position)
  211.             .label(label)
  212.             .build();

  213.         errors.addError(error);
  214.     }

  215.     /**
  216.      * フィールドの値が空かどうか。
  217.      * <p>値がnullまたは、文字列の場合空文字のとき、空と判定する。
  218.      * @return trueの場合、値は空。
  219.      */
  220.     public boolean isInputEmpty() {
  221.         if(fieldValue == null || fieldValue.toString().isEmpty()) {
  222.             return true;
  223.         }

  224.         return false;
  225.     }

  226.     /**
  227.      * フィールドに対してエラーが存在するかどうか。
  228.      * @return trueの場合、エラーが存在する。
  229.      */
  230.     public boolean hasErrors() {
  231.         return errors.hasFieldErrors(fieldName);
  232.     }

  233.     /**
  234.      * フィールドに対してエラーが存在しなかどうか。
  235.      * @return trueの場合、エラーが存在しない。
  236.      */
  237.     public boolean hasNotErrors() {
  238.         return !hasErrors();
  239.     }

  240.     /**
  241.      * エラー情報を取得する。
  242.      * @return エラー情報
  243.      */
  244.     public SheetBindingErrors<?> getBindingErrors() {
  245.         return errors;
  246.     }

  247.     /**
  248.      * フィールドの名称を取得する
  249.      * @return フィールドの名称
  250.      */
  251.     public String getFieldName() {
  252.         return fieldName;
  253.     }

  254.     /**
  255.      * フィールドの値を取得する。
  256.      * @return フィールドの値。
  257.      */
  258.     public T getValue() {
  259.         return fieldValue;
  260.     }

  261.     /**
  262.      * フィールドのクラスタイプを取得する。
  263.      * @return クラスタイプ
  264.      */
  265.     public Class<T> getType() {
  266.         return fieldType;
  267.     }

  268.     /**
  269.      * フィールドのJavaBean上のパスを取得する。
  270.      * @return フィールドのJavaBean上のパス
  271.      */
  272.     public String getFieldPath() {
  273.         return fieldPath;
  274.     }

  275.     /**
  276.      * セルの位置情報を取得します。
  277.      * <p>位置情報の取得用のフィールドやメソッドがbeanに定義されている場合は、コンストラクタの呼び出し時に設定されています。</p>
  278.      * @return 自身のインスタンス。
  279.      */
  280.     public CellPosition getPosition() {
  281.         return position;
  282.     }

  283.     /**
  284.      * セルの位置情報を設定します。
  285.      * @param position セルの位置情報
  286.      */
  287.     public void setPosition(CellPosition position) {
  288.         this.position = position;
  289.     }

  290.     /**
  291.      * セルのラベル情報を取得します。
  292.      * <p>ラベル情報の取得用のフィールドやメソッドがbeanに定義されている場合は、コンストラクタの呼び出し時に設定されています。</p>
  293.      * @return 自身のインスタンス。
  294.      */
  295.     public String getLabel() {
  296.         return label;
  297.     }

  298.     /**
  299.      * セルのラベル情報を設定します。
  300.      * @param label セルのラベル情報
  301.      */
  302.     public void setLabel(String label) {
  303.         this.label = label;
  304.     }

  305.     /**
  306.      * フォーマッタを取得する。
  307.      * @return フォーマッタ。
  308.      *         デフォルトでは、フィールドのクラスタイプ、付与されたアノテーションを元にしたもの。
  309.      *
  310.      */
  311.     public FieldFormatter<T> getFormatter() {
  312.         return formatter;
  313.     }

  314.     /**
  315.      * フォーマッタを設定する。
  316.      * @param formatter
  317.      */
  318.     public void setFormatter(FieldFormatter<T> formatter) {
  319.         this.formatter = formatter;
  320.     }
  321. }