boolean isValid(Object, ConstraintValidatorContext)
ビジネス ロジックを実行し、そのロジックに応じて true/false を返すカスタム Bean バリデーターを実装しています。
私ができるようにしたいのは、スローされる ConstraintViolation 例外にデータを追加することです。それをキャッチして処理する例外ハンドラーは、それを引き起こしたエラー/引数に関する詳細を含むこの余分なデータを引き出すことができます。現在、これらの動的な詳細がない違反にのみメッセージを関連付けることができます。
たとえば、isValid に渡されるオブジェクトには、バリデーターによって内容が検証されるマップが含まれます。バリデーター API はブール値のみを返すため、マップのどのメンバーが制約違反をトリガーしたかの粒度が失われます。この情報を保存して転送できる方法を探しています。
EDIT 8/13/2013 - JAX-RS を含むソリューション例
(この質問に関係のないJAXBの詳細を一部省略しています)
FooParam.java
public class FooParam {
private Map<String, String> subParamMap;
public Map<String, String> getSubParamMap() { return this.subParamMap; }
public void setSubParamMap(Map<String, String> subParamMap) {
this.subParamMap = subParamMap;
}
public FooParam() { this.subParamMap = new HashMap<>(); }
}
FooResource.java
public class FooResource {
...
public void doSomething(@CheckValidParam(value=FooResoure.class) FooParam fooParam) {
...
}
}
CheckValidParam.java
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = CheckValidParamValidator.class)
@Documented
public @interface CheckValidParam{
String message() default "{com.foo.bar.CheckValidParam.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
Class<?> value();
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface List {
CheckValidParam[] value();
}
}
CheckValidParamValidator.java
public class CheckValidParamValidator implements ConstraintValidator<CheckValidParam, FooParam> {
private Class<?> entityClass;
@Override
public void initialize(CheckValidParam checkValidParam ) {
this.entityClass = checkValidParam.value();
}
@Override
public boolean isValid(FooParam fooParam, ConstraintValidatorContext constraintValidatorContext) {
String message = constraintValidatorContext.getDefaultConstraintMessageTemplate();
constraintValidatorContext.disableDefaultConstraintViolation();
boolean isValid = true;
Map<String, String> subParamMap = fooParam.getSubParamMap();
for (Map.Entry<String, String> entry : subParamMap.entrySet()) {
//Contrived validation logic
if (entry.getValue().equalsIgnoreCase("junk")) {
constraintValidatorContext.buildConstraintViolationWithTemplate(message)
.addNode(entry.getKey()).addConstraintViolation();
isValid = false;
}
}
return isValid;
}
}
JAX-RS パイプラインでスローされた MethodConstraintViolationExceptions をインターセプトするクラスの簡素化されたバージョン。無効なパラメーターと関連するエラー メッセージを引き出すことを示しています。
MethodConstraintValidationMapper.java
@Provider
public class MethodConstraintValidationMapperimplements ExceptionMapper<MethodConstraintViolationException> {
private static final Logger log = Logger.getLogger(MethodConstraintValidationMapper.class);
@Override
public Response toResponse(MethodConstraintViolationException ex) {
Response response;
Set<MethodConstraintViolation<?>> violations = ex.getConstraintViolations();
List<ValidationExceptionError> errors = new ArrayList<>();
for (MethodConstraintViolation<?> methodConstraintViolation : ex.getConstraintViolations()) {
ValidationExceptionError error = new ValidationExceptionError();
error.setFieldName(((PathImpl) methodConstraintViolation.getPropertyPath()).getLeafNode().asString());
error.setErrorMessage(methodConstraintViolation.getMessage());
errors.add(error);
}
return Response.status(Response.Status.PRECONDITION_FAILED).entity(new GenericEntity<List<ValidationExceptionError>>(errors) {}).type(MediaType.APPLICATION_JSON).build();
}
}