Spring MVCというか、JSR-303でメソッドを使用したヴァリデーション
メンバaの値が条件Aでメンバbの値が条件Bだったら、メンバcの値は条件Cの時のみ許可する、みたいな複雑な条件を行う時の話について。
メソッドで判定処理を書けば簡単に済む場合の、メソッドを使ったヴァリデーターの作成方法。
実装
アノテーションと実装はこんな感じのものを用意。
@Target({ METHOD, FIELD, TYPE, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) @Retention(RUNTIME) @Constraint(validatedBy = ValidationMethodValidator.class) @Documented public @interface ValidationMethod { String message() default "{smart.extension.spring.validator.ValidationMethod.message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; String method(); String target() default ""; @Target({ METHOD, FIELD, TYPE, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) @Retention(RUNTIME) @Documented @interface List { ValidationMethod[] value(); } }
public class ValidationMethodValidator implements ConstraintValidator<ValidationMethod, Object> { private String method; private String target; @Override public void initialize(final ValidationMethod constraintAnnotation) { method = constraintAnnotation.method(); target = constraintAnnotation.target(); } @Override public boolean isValid(final Object value, final ConstraintValidatorContext context) { boolean isValid = false; if (value != null) { try { Method m = value.getClass().getMethod(method); isValid = (Boolean)m.invoke(value); } catch (Exception e) { throw new WrapRuntimeException(e); } } if (!isValid) { context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()).addNode(target).addConstraintViolation() .disableDefaultConstraintViolation(); } return isValid; } }
サンプル
typeが1か2だったらdataは空以外を、typeが1か2以外だったらdataは空を要求するような場合の記述はこんな感じで。
@ValidationMethod(method = "validateData", target = "data") public static class Data { private int type; private String data; ... public boolean validateData() { if ((type == 1) || (type == 2)) { return !StringUtil.isEmpty(data); } else { return StringUtil.isEmpty(data); } } }
targetは、前回のFieldCompareValidatorの話に同じでどのメンバのエラーにするかの設定だす(・ω・)