Issue
In Java Spring boot i made class custome validator. And if even one field fail in Validator i get always both error messages
[ "WRONG_CAR_COLOR", "WRONG_YEAR_OF_PRODUCTION" ]
public class ElectricCarSpecValidator implements ConstraintValidator<ElectricCarSpec, CreateCarCommand> {
private static final Integer minYearOfProduction = 2000;
private static final Integer carColorRed = 10;
private static final Integer electricCarId = 5;
@Override
public boolean isValid(CreateCarCommand command, ConstraintValidatorContext context) {
if (!command.getFuelTypeId().equals(electricCarId)) {
return true;
}
return command.getYearOfProduction() >= minYearOfProduction && !command.getCarColorId().equals(carColorRed);
}
Validator:
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex) {
List<String> errors = ex.getAllErrors().stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.toList());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errors);
}
Adnotation:
@ElectricCarSpec.List({
@ElectricCarSpec(field = "yearOfProduction", message = "WRONG_YEAR_OF_PRODUCTION"),
@ElectricCarSpec(field = "carColorId", message = "WRONG_CAR_COLOR")
})
Solution
The problem is that whatever field you specify, you always do the very same validation - checking if both fields are valid.
return command.getYearOfProduction() >= minYearOfProduction
&& !command.getCarColorId().equals(carColorRed);
In order to take your field
property into account, you would need to override initialize(A constraintAnnotation). It's guaranteed by the docs to be called before isValid
.
Initializes the validator in preparation for isValid(Object, ConstraintValidatorContext) calls. The constraint annotation for a given constraint declaration is passed. This method is guaranteed to be called before any use of this instance for validation.
Something like this:
public class TestConstraintValidator implements ConstraintValidator<ElectricCarSpec, CreateCarCommand> {
private String field;
@Override
public void initialize(ElectricCarSpec constraintAnnotation) {
this.field = constraintAnnotation.field();
}
@Override
public boolean isValid(CreateCarCommand value, ConstraintValidatorContext context) {
if (field.equals("yearOfProduction")) {
//validate year of production
}
if (field.equals("carColorId")) {
//validate color id
}
return true;
}
}
Having few if
s for every field you want to validate is fine, but if there are too many fields to check, you may consider writing a strategy pattern to pick correct validation strategy depending on field name.
Answered By - Chaosfire
Answer Checked By - Candace Johnson (JavaFixing Volunteer)