4

How do you wire Spring Validation Errors to error strings in messages.properties?

  • My Validator throws a custom RuntimeException that wraps the spring Errors object.
  • My @ControllerAdvice intercepts the exception and transforms the RuntimeException into a DTO object called WebExceptionMessage.
  • The DTO WebExceptionMessage object has a List of custom WebValidationError objects that are transformations of the Spring Errors object.
  • I have messages.properties in my classpath with keys that match the error codes in the Spring Validation Errors object.

How, when and where are the Spring Validation Errors agumented with the values found in messages.properties?

I read all about automagic wirings and tried them but whatever I do it doesn't work...

enter image description here

src/main/resources/messages.properties

field.required=Missing mandatory field.
field.numeric_only=Field must contain numbers only.
// more

MyValidator.java

@Component
public class MyValidator implements Validator{
  // code
  public void validate(Object target, Errors errors) {
    ValidationUtils.rejectIfEmpty(errors, "audit", "field.required");
    if(errors.hasErrors()){
      throw new MyRuntimeException(MyErrorCode.INVALID_REQUEST, "Failed Validator").errors(errors);
    }   
  }
}

WebExceptionHandler.java

@ControllerAdvice
public class WebExceptionHandler {
  @ExceptionHandler(value=MyRuntimeException.class)
  public ResponseEntity<WebExceptionMessage> myRuntimeException(MyRuntimeException e){
    WebExceptionMessage msg = new WebExceptionMessage();

    // code

    if(e.hasErrors()){
      List<WebValidationError> errors = new ArrayList<WebValidationError>();
      List<FieldError> fieldErrors = e.getErrors().getFieldErrors();
      for(FieldError err : fieldErrors){

        // =============================
        // I think somewhere over here I need to map the err.getCode()
        // to the value in messages.properties but isn't spring supposed 
        // to "magically" do that somehow and place the value in err.getDefaultMessage()
        //
        // I am probably completely off base here...please advise.
        // =============================

        errors.add(new WebValidationError(err.getCode(), err.getField(), err.getDefaultMessage()));


      }
      msg.setErrors(errors);
    }

    return new ResponseEntity<WebExceptionMessage>(msg, e.getErrorCode().getStatus());
  }
}

MyRuntimeException.java

public class MyRuntimeException extends RuntimeException {
  private org.springframework.validation.Errors errors;
  // code
  public MyRuntimeException errors(final Errors errors){
    this.errors = errors;
    return this;
  }  
}

WebExceptionMessage.java

public class WebExceptionMessage implements Serializable{
  // code
  private List<WebValidationError> errors;
}

1 Answer 1

3

I figured it out! I just autowired the MessageSource into my @ControllerAdvice and did the lookup "manually". This works but I thought spring (or spring-boot?) is suppose to do this automatically?

enter image description here

@ControllerAdvice
public class WebExceptionHandler {

  @Autowired
  MessageSource errorMessageSource;

  @ExceptionHandler(value=MyRuntimeException.class)
  public ResponseEntity<WebExceptionMessage> myRuntimeException(MyRuntimeException e){
    WebExceptionMessage msg = new WebExceptionMessage();

    // code

    if(e.hasErrors()){
      List<WebValidationError> errors = new ArrayList<WebValidationError>();
      List<FieldError> fieldErrors = e.getErrors().getFieldErrors();
      for(FieldError err : fieldErrors){

        // =============================
        // "Manually" extract the message.
        // =============================
        String message = errorMessageSource.getMessage(err.getCode(), err.getArguments(), null);
        errors.add(new WebValidationError(err.getCode(), err.getField(), message));


      }
      msg.setErrors(errors);
    }

    return new ResponseEntity<WebExceptionMessage>(msg, e.getErrorCode().getStatus());
  }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.