概要
汎用Validator
内容
汎用的なValidatorを作成します。
要件は以下とします。
・1つのValidatorの中に複数のエラー判定処理が存在する
それぞれのエラー判定のどれか一つのエラーが成立した場合に
Validator全体としてはエラーとする。
・各エラー判定処理は前提条件が存在する
それぞれのエラー判定は前提条件が存在し、前提条件が成立しない場合は
無条件で正常とする。
※前提条件が存在しない場合もあり
・エラーごとにエラーコードが存在する
各エラーはそれぞれ対応するエラーコードがある。
上記のような要件のValidatorを作成する機会が多く、
一つのValidator内で大量のチェックを行う場合は
このサンプルのような形式が役に立ちます。
クラス構成
gr.java_conf.tb.tbpg_util.validator
│ ValidationResult.java : Validatorの結果保存用クラス
│
├─checker
│ │ BaseIsSameValueChecker.java : 同値チェック用基底クラス
│ │ BigDecimalIsSameValueChecker.java : BigDecimal同値チェック用クラス
│ │ IntegerIsSameValueChecker.java : Integer同値チェック用クラス
│ │ StringIsSameValueChecker.java : String同値チェック用クラス
│ │
│ └─intf
│ ValidationCheckerIntf.java : 個別チェック用インターフェース
│
├─manager
│ ValidationManager.java : Validation管理用インターフェース
│
├─sample
│ ├─data
│ │ SampleData.java : 動作確認用サンプルデータ
│ │
│ ├─target
│ │ ATargetChecker.java : サンプルターゲットチェッカー
│ │
│ └─validator
│ │ SampleValidator.java : サンプルValidator
│ │ SampleValidatorTest.java : サンプルValidatorテストクラス
│ │
│ └─intf
│ SampleValidatorIntf.java : サンプルValidatorのインターフェース
│
└─target
│ NullTargetChecker.java : チェックなし用ターゲットチェッカー
│
└─intf
TargetCheckerIntf.java : ターゲットチェッカー用インターフェース
サンプルケース
gr.java_conf.tb.tbpg_util.validatorパッケージ
ValidationResult.java
package gr.java_conf.tb.tbpg_util.validator; /** * Validation結果保存用クラス. * * @author tbpg * */ public class ValidationResult { /** エラーコード */ private String errorCode; /** * デフォルトコンストラクタ. */ public ValidationResult() { super(); } public boolean hasError() { return this.errorCode != null; } /** * errorCodeを取得する。 * * @return errorCode */ public String getErrorCode() { return errorCode; } /** * errorCodeを設定する. * * @param errorCode セットする errorCode */ public void setErrorCode(String errorCode) { this.errorCode = errorCode; } }
gr.java_conf.tb.tbpg_util.validator.checkerパッケージ
BaseIsSameValueChecker
package gr.java_conf.tb.tbpg_util.validator.checker; public class BaseIsSameValueChecker<V> { V value; V compare; public BaseIsSameValueChecker(V value, V compare) { this.value = value; this.compare = compare; } }
BigDecimalIsSameValueChecker
package gr.java_conf.tb.tbpg_util.validator.checker; import gr.java_conf.tb.tbpg_util.validator.checker.intf.ValidationCheckerIntf; import java.math.BigDecimal; /** * BigDecimalが同じ値であることを確認するチェッカー。 * */ public class BigDecimalIsSameValueChecker extends BaseIsSameValueChecker<BigDecimal> implements ValidationCheckerIntf { /** * @param value * @param compare */ public BigDecimalIsSameValueChecker(BigDecimal value, BigDecimal compare) { super(value, compare); this.value = value; this.compare = compare; } @Override public boolean isValid() { if (value == null && compare != null) { return false; } if (value != null && compare == null) { return false; } if (value == null && compare == null) { return true; } return value.equals(compare); } }
IntegerIsSameValueChecker
package gr.java_conf.tb.tbpg_util.validator.checker; import gr.java_conf.tb.tbpg_util.validator.checker.intf.ValidationCheckerIntf; /** * Integerが同じ値であることを確認するチェッカー。 * */ public class IntegerIsSameValueChecker extends BaseIsSameValueChecker<Integer> implements ValidationCheckerIntf { /** * @param value * @param compare */ public IntegerIsSameValueChecker(Integer value, Integer compare) { super(value, compare); this.value = value; this.compare = compare; } @Override public boolean isValid() { if (value == null && compare != null) { return false; } if (value != null && compare == null) { return false; } if (value == null && compare == null) { return true; } return value.equals(compare); } }
StringIsSameValueChecker
package gr.java_conf.tb.tbpg_util.validator.checker; import gr.java_conf.tb.tbpg_util.validator.checker.intf.ValidationCheckerIntf; /** * Stringが同じ値であることを確認するチェッカー。 * */ public class StringIsSameValueChecker extends BaseIsSameValueChecker<String> implements ValidationCheckerIntf { /** * @param value * @param compare */ public StringIsSameValueChecker(String value, String compare) { super(value, compare); this.value = value; this.compare = compare; } @Override public boolean isValid() { if (value == null && compare != null) { return false; } if (value != null && compare == null) { return false; } if (value == null && compare == null) { return true; } return value.equals(compare); } }
gr.java_conf.tb.tbpg_util.validator.checker.intfパッケージ
ValidationCheckerIntf
package gr.java_conf.tb.tbpg_util.validator.checker.intf; /** * Validation内部の個別Validatoion判定用インターフェース。 * * <pre> * 複数のValidationからなるValidatorの内部にある個別の * Validationを表すインターフェース * </pre> * */ public interface ValidationCheckerIntf { /** * 個別Validationが正当な値かどうか確認する。 * * @return 正当な値ならtrue,不当な値ならfalse */ boolean isValid(); }
gr.java_conf.tb.tbpg_util.validator.managerパッケージ
ValidationManager
package gr.java_conf.tb.tbpg_util.validator.manager; import gr.java_conf.tb.tbpg_util.validator.checker.intf.ValidationCheckerIntf; import gr.java_conf.tb.tbpg_util.validator.target.NullTargetChecker; import gr.java_conf.tb.tbpg_util.validator.target.intf.TargetCheckerIntf; /** * Validationの個別部品の事前条件,チェック内容,エラーコードを管理するクラス. * */ public class ValidationManager { /** Validationのターゲット判定(デフォルトはチェックなし). */ TargetCheckerIntf targetChecker = new NullTargetChecker(); /** Validation内容. */ ValidationCheckerIntf validationChecker; /** Validationエラーコード. */ String errorCode; public ValidationManager targetChecker(TargetCheckerIntf targetChecker) { this.targetChecker = targetChecker; return this; } public ValidationManager validationChecker(ValidationCheckerIntf validationChecker) { this.validationChecker = validationChecker; return this; } public ValidationManager errorCode(String errorCode) { this.errorCode = errorCode; return this; } public TargetCheckerIntf getTargetChecker() { return targetChecker; } public ValidationCheckerIntf getValidationChecker() { return validationChecker; } public String getErrorCode() { return errorCode; } }
gr.java_conf.tb.tbpg_util.validator.sample.dataパッケージ
SampleData
package gr.java_conf.tb.tbpg_util.validator.sample.data; import java.math.BigDecimal; public class SampleData { String a; String b; String c; String d; String e; Integer f; Integer g; Integer h; Integer i; Integer j; BigDecimal k; BigDecimal l; BigDecimal m; BigDecimal n; BigDecimal o; public String getA() { return a; } public void setA(String a) { this.a = a; } public String getB() { return b; } public void setB(String b) { this.b = b; } public String getC() { return c; } public void setC(String c) { this.c = c; } public String getD() { return d; } public void setD(String d) { this.d = d; } public String getE() { return e; } public void setE(String e) { this.e = e; } public Integer getF() { return f; } public void setF(Integer f) { this.f = f; } public Integer getG() { return g; } public void setG(Integer g) { this.g = g; } public Integer getH() { return h; } public void setH(Integer h) { this.h = h; } public Integer getI() { return i; } public void setI(Integer i) { this.i = i; } public Integer getJ() { return j; } public void setJ(Integer j) { this.j = j; } public BigDecimal getK() { return k; } public void setK(BigDecimal k) { this.k = k; } public BigDecimal getL() { return l; } public void setL(BigDecimal l) { this.l = l; } public BigDecimal getM() { return m; } public void setM(BigDecimal m) { this.m = m; } public BigDecimal getN() { return n; } public void setN(BigDecimal n) { this.n = n; } public BigDecimal getO() { return o; } public void setO(BigDecimal o) { this.o = o; } }
gr.java_conf.tb.tbpg_util.validator.sample.targetパッケージ
ATargetChecker
package gr.java_conf.tb.tbpg_util.validator.sample.target; import gr.java_conf.tb.tbpg_util.validator.target.intf.TargetCheckerIntf; /** * Aの事前条件用のターゲットチェッカー。 * * */ public class ATargetChecker implements TargetCheckerIntf { String b; public ATargetChecker(String b) { this.b = b; } /** * bがnullではない場合のみチェックする */ @Override public boolean isTarget() { return (b != null); } }
gr.java_conf.tb.tbpg_util.validator.sample.validatorパッケージ
SampleValidator
package gr.java_conf.tb.tbpg_util.validator.sample.validator; import gr.java_conf.tb.tbpg_util.validator.ValidationResult; import gr.java_conf.tb.tbpg_util.validator.checker.BigDecimalIsSameValueChecker; import gr.java_conf.tb.tbpg_util.validator.checker.IntegerIsSameValueChecker; import gr.java_conf.tb.tbpg_util.validator.checker.StringIsSameValueChecker; import gr.java_conf.tb.tbpg_util.validator.manager.ValidationManager; import gr.java_conf.tb.tbpg_util.validator.sample.data.SampleData; import gr.java_conf.tb.tbpg_util.validator.sample.target.ATargetChecker; import gr.java_conf.tb.tbpg_util.validator.sample.validator.intf.SampleValidatorIntf; import java.util.ArrayList; import java.util.List; public class SampleValidator implements SampleValidatorIntf { private SampleData sampleData; private SampleData compare; public SampleValidator(SampleData sampleData, SampleData compare) { this.sampleData = sampleData; this.compare = compare; } @Override public ValidationResult validate(ValidationResult result) { List<ValidationManager> managers = getValidationManagers(); for (int i = 0; i < managers.size(); i++) { // 前提 if (managers.get(i).getTargetChecker().isTarget()) { // 比較 if (!managers.get(i).getValidationChecker().isValid()) { result.setErrorCode(managers.get(i).getErrorCode()); return result; } } } return result; } private List<ValidationManager> getValidationManagers() { List<ValidationManager> managers = new ArrayList<ValidationManager>(); managers.add(new ValidationManager().targetChecker(new ATargetChecker(sampleData.getB())) .validationChecker(new StringIsSameValueChecker(sampleData.getA(), compare.getA())).errorCode("error A")); managers.add(new ValidationManager().validationChecker( new StringIsSameValueChecker(sampleData.getB(), compare.getB())).errorCode("error B")); managers.add(new ValidationManager().validationChecker( new StringIsSameValueChecker(sampleData.getC(), compare.getC())).errorCode("error C")); managers.add(new ValidationManager().validationChecker( new StringIsSameValueChecker(sampleData.getD(), compare.getD())).errorCode("error D")); managers.add(new ValidationManager().validationChecker( new StringIsSameValueChecker(sampleData.getE(), compare.getE())).errorCode("error E")); managers.add(new ValidationManager().validationChecker( new IntegerIsSameValueChecker(sampleData.getF(), compare.getF())).errorCode("error F")); managers.add(new ValidationManager().validationChecker( new IntegerIsSameValueChecker(sampleData.getG(), compare.getG())).errorCode("error G")); managers.add(new ValidationManager().validationChecker( new IntegerIsSameValueChecker(sampleData.getH(), compare.getH())).errorCode("error H")); managers.add(new ValidationManager().validationChecker( new IntegerIsSameValueChecker(sampleData.getI(), compare.getI())).errorCode("error I")); managers.add(new ValidationManager().validationChecker( new IntegerIsSameValueChecker(sampleData.getJ(), compare.getJ())).errorCode("error J")); managers.add(new ValidationManager().validationChecker( new BigDecimalIsSameValueChecker(sampleData.getK(), compare.getK())).errorCode("error K")); managers.add(new ValidationManager().validationChecker( new BigDecimalIsSameValueChecker(sampleData.getL(), compare.getL())).errorCode("error L")); managers.add(new ValidationManager().validationChecker( new BigDecimalIsSameValueChecker(sampleData.getM(), compare.getM())).errorCode("error M")); managers.add(new ValidationManager().validationChecker( new BigDecimalIsSameValueChecker(sampleData.getN(), compare.getN())).errorCode("error N")); managers.add(new ValidationManager().validationChecker( new BigDecimalIsSameValueChecker(sampleData.getO(), compare.getO())).errorCode("error O")); return managers; } }
gr.java_conf.tb.tbpg_util.validator.sample.validator.intfパッケージ
SampleValidatorIntf
package gr.java_conf.tb.tbpg_util.validator.sample.validator.intf; import gr.java_conf.tb.tbpg_util.validator.ValidationResult; public interface SampleValidatorIntf { ValidationResult validate(ValidationResult result); }
gr.java_conf.tb.tbpg_util.validator.targetパッケージ
NullTargetChecker
package gr.java_conf.tb.tbpg_util.validator.target; import gr.java_conf.tb.tbpg_util.validator.target.intf.TargetCheckerIntf; /** * 事前条件なしの場合用のターゲットチェッカー。 * * */ public class NullTargetChecker implements TargetCheckerIntf { @Override public boolean isTarget() { return true; } }
gr.java_conf.tb.tbpg_util.validator.target.intfパッケージ
package gr.java_conf.tb.tbpg_util.validator.target.intf; /** * Validationの事前条件判定用ターゲットチェッカー。 * * <pre> * 処理対象の場合にtrue,処理対象外の場合はfalseを返却するisTargetメソッドを持つ。 * </pre> * */ public interface TargetCheckerIntf { boolean isTarget(); }
テストコード
SampleValidatorTest
package gr.java_conf.tb.tbpg_util.validator.sample.validator; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import gr.java_conf.tb.tbpg_util.common.CommonUtil; import gr.java_conf.tb.tbpg_util.validator.ValidationResult; import gr.java_conf.tb.tbpg_util.validator.sample.data.SampleData; import java.math.BigDecimal; import org.junit.experimental.runners.Enclosed; import org.junit.experimental.theories.DataPoints; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; import org.junit.runner.RunWith; @RunWith(Enclosed.class) public class SampleValidatorTest { @RunWith(Theories.class) public static class Validate { /** * SampleValidatorTestのFixture * * @author sample * */ public static class Fixture { /** caseNo. */ int caseNo; /** a. */ String a; /** b. */ String b; /** c. */ String c; /** d. */ String d; /** e. */ String e; /** f. */ Integer f; /** g. */ Integer g; /** h. */ Integer h; /** i. */ Integer i; /** j. */ Integer j; /** k. */ BigDecimal k; /** l. */ BigDecimal l; /** m. */ BigDecimal m; /** n. */ BigDecimal n; /** o. */ BigDecimal o; /** compare_a */ String compare_a; /** compare_b */ String compare_b; /** compare_c */ String compare_c; /** compare_d */ String compare_d; /** compare_e */ String compare_e; /** compare_f */ Integer compare_f; /** compare_g */ Integer compare_g; /** compare_h */ Integer compare_h; /** compare_i */ Integer compare_i; /** compare_j */ Integer compare_j; /** compare_k */ BigDecimal compare_k; /** compare_l */ BigDecimal compare_l; /** compare_m */ BigDecimal compare_m; /** compare_n */ BigDecimal compare_n; /** compare_o */ BigDecimal compare_o; boolean hasError; String errorCode; public Fixture caseNo(int caseNo) { this.caseNo = caseNo; return this; } public Fixture a(String a) { this.a = a; return this; } public Fixture b(String b) { this.b = b; return this; } public Fixture c(String c) { this.c = c; return this; } public Fixture d(String d) { this.d = d; return this; } public Fixture e(String e) { this.e = e; return this; } public Fixture f(Integer f) { this.f = f; return this; } public Fixture g(Integer g) { this.g = g; return this; } public Fixture h(Integer h) { this.h = h; return this; } public Fixture i(Integer i) { this.i = i; return this; } public Fixture j(Integer j) { this.j = j; return this; } public Fixture k(BigDecimal k) { this.k = k; return this; } public Fixture l(BigDecimal l) { this.l = l; return this; } public Fixture m(BigDecimal m) { this.m = m; return this; } public Fixture n(BigDecimal n) { this.n = n; return this; } public Fixture o(BigDecimal o) { this.o = o; return this; } public Fixture compare_a(String compare_a) { this.compare_a = compare_a; return this; } public Fixture compare_b(String compare_b) { this.compare_b = compare_b; return this; } public Fixture compare_c(String compare_c) { this.compare_c = compare_c; return this; } public Fixture compare_d(String compare_d) { this.compare_d = compare_d; return this; } public Fixture compare_e(String compare_e) { this.compare_e = compare_e; return this; } public Fixture compare_f(Integer compare_f) { this.compare_f = compare_f; return this; } public Fixture compare_g(Integer compare_g) { this.compare_g = compare_g; return this; } public Fixture compare_h(Integer compare_h) { this.compare_h = compare_h; return this; } public Fixture compare_i(Integer compare_i) { this.compare_i = compare_i; return this; } public Fixture compare_j(Integer compare_j) { this.compare_j = compare_j; return this; } public Fixture compare_k(BigDecimal compare_k) { this.compare_k = compare_k; return this; } public Fixture compare_l(BigDecimal compare_l) { this.compare_l = compare_l; return this; } public Fixture compare_m(BigDecimal compare_m) { this.compare_m = compare_m; return this; } public Fixture compare_n(BigDecimal compare_n) { this.compare_n = compare_n; return this; } public Fixture compare_o(BigDecimal compare_o) { this.compare_o = compare_o; return this; } public Fixture errorCode(String errorCode) { this.errorCode = errorCode; return this; } public Fixture hasError(boolean hasError) { this.hasError = hasError; return this; } public String toString() { // Fixtureの内容を一括出力 return CommonUtil.getAllFiledInfo(this); } } @DataPoints public static Fixture[] getFixture() { Fixture[] fixture = { // 正常系 new Fixture().caseNo(1).a("a").b("b").c("c").d("d").e("e").f(1).g(2).h(3).i(4).j(5).k(new BigDecimal(6)) .l(new BigDecimal(7)).m(new BigDecimal(8)).n(new BigDecimal(9)).o(new BigDecimal(10)).compare_a("a") .compare_b("b").compare_c("c").compare_d("d").compare_e("e").compare_f(1).compare_g(2).compare_h(3) .compare_i(4).compare_j(5).compare_k(new BigDecimal(6)).compare_l(new BigDecimal(7)) .compare_m(new BigDecimal(8)).compare_n(new BigDecimal(9)).compare_o(new BigDecimal(10)).hasError(false) .errorCode(""), // 異常系(Aが異なる) new Fixture().caseNo(2).a("b").b("b").c("c").d("d").e("e").f(1).g(2).h(3).i(4).j(5).k(new BigDecimal(6)) .l(new BigDecimal(7)).m(new BigDecimal(8)).n(new BigDecimal(9)).o(new BigDecimal(10)).compare_a("a") .compare_b("b").compare_c("c").compare_d("d").compare_e("e").compare_f(1).compare_g(2).compare_h(3) .compare_i(4).compare_j(5).compare_k(new BigDecimal(6)).compare_l(new BigDecimal(7)) .compare_m(new BigDecimal(8)).compare_n(new BigDecimal(9)).compare_o(new BigDecimal(10)).hasError(true) .errorCode("error A"), // 正常系(Aが異なるが前提となるBがnull) new Fixture().caseNo(3).a("b").b(null).c("c").d("d").e("e").f(1).g(2).h(3).i(4).j(5).k(new BigDecimal(6)) .l(new BigDecimal(7)).m(new BigDecimal(8)).n(new BigDecimal(9)).o(new BigDecimal(10)).compare_a("a") .compare_b(null).compare_c("c").compare_d("d").compare_e("e").compare_f(1).compare_g(2).compare_h(3) .compare_i(4).compare_j(5).compare_k(new BigDecimal(6)).compare_l(new BigDecimal(7)) .compare_m(new BigDecimal(8)).compare_n(new BigDecimal(9)).compare_o(new BigDecimal(10)).hasError(false) .errorCode(""), }; return fixture; }; @Theory public void testValidate(Fixture fixture) { /*--- 初期化 ---*/ SampleData sampleData = getSampleData(fixture); SampleData compare = getCompare(fixture); SampleValidator validator = new SampleValidator(sampleData, compare); ValidationResult result = new ValidationResult(); /*--- 実行 ---*/ result = validator.validate(result); /*--- 検証 ---*/ assertThat(fixture.toString(), result.hasError(), is(fixture.hasError)); if (fixture.hasError) { assertThat(fixture.toString(), result.getErrorCode(), is(fixture.errorCode)); } } private SampleData getSampleData(Fixture fixture) { SampleData sampleData = new SampleData(); sampleData.setA(fixture.a); sampleData.setB(fixture.b); sampleData.setC(fixture.c); sampleData.setD(fixture.d); sampleData.setE(fixture.e); sampleData.setF(fixture.f); sampleData.setG(fixture.g); sampleData.setH(fixture.h); sampleData.setI(fixture.i); sampleData.setJ(fixture.j); sampleData.setK(fixture.k); sampleData.setL(fixture.l); sampleData.setM(fixture.m); sampleData.setN(fixture.n); sampleData.setO(fixture.o); return sampleData; } private SampleData getCompare(Fixture fixture) { SampleData sampleData = new SampleData(); sampleData.setA(fixture.compare_a); sampleData.setB(fixture.compare_b); sampleData.setC(fixture.compare_c); sampleData.setD(fixture.compare_d); sampleData.setE(fixture.compare_e); sampleData.setF(fixture.compare_f); sampleData.setG(fixture.compare_g); sampleData.setH(fixture.compare_h); sampleData.setI(fixture.compare_i); sampleData.setJ(fixture.compare_j); sampleData.setK(fixture.compare_k); sampleData.setL(fixture.compare_l); sampleData.setM(fixture.compare_m); sampleData.setN(fixture.compare_n); sampleData.setO(fixture.compare_o); return sampleData; } } }