1

I have the following @ControllerAdvice:

@ControllerAdvice
public class ExceptionHandlingController {

    @ExceptionHandler(value = { MethodArgumentNotValidException.class,
            EntityExistsException.class, BadCredentialsException.class, MismatchedInputException.class })
    public ResponseEntity<ExceptionResponse> invalidInput(RuntimeException ex) {
        ExceptionResponse response = new ExceptionResponse();
        response.setErrorCode("BAD_REQUEST");
        response.setErrorMessage(ex.getMessage());
        return new ResponseEntity<ExceptionResponse>(response,
                HttpStatus.BAD_REQUEST);
    }

}

And the validator is bound to the controller this way:

@RestController
@RequestMapping("/api/authentication")
public class UserAccountControllerImpl implements UserAccountController {

    @Autowired
    private UserAccountService userAccountService;

    @Override
    public UserAccountEntity login(@Valid @RequestBody UserAccountEntity account,
            HttpServletResponse response) throws BadCredentialsException {
        return userAccountService.authenticateUserAndSetResponsenHeader(
                account.getUsername(), account.getPassword(), response);
    }

    @Override
    public UserAccountEntity create(@Valid @RequestBody UserAccountEntity userAccount,
            HttpServletResponse response) throws EntityExistsException {
        String username = userAccount.getUsername();
        String password = userAccount.getPassword();
        userAccountService.saveIfNotExists(username, password);
        return userAccountService.authenticateUserAndSetResponsenHeader(
                username, password, response);
    }

    //used to bind the validator to the incoming request
    @InitBinder
    public void binder(WebDataBinder binder) {
        binder.addValidators(new UserAccountValidator());
    }
}

And this is the UserAccountValidator used to validate the incoming UserAccountEntity:

public class UserAccountValidator implements Validator {

    @Override
    public boolean supports(Class<?> clazz) {
        return UserAccountEntity.class.equals(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        UserAccountEntity userAccount = (UserAccountEntity) target;
        String password = userAccount.getPassword();
        String username = userAccount.getUsername();
        EmailValidator emailValidator = EmailValidator.getInstance();
        if (!emailValidator.isValid(username)) {
            errors.reject("Username must be a valid email address");
        }
        if (password.length() > 30 || password.length() < 8) {
            errors.reject("Password must be at least 8 and at most 30 characters");
        }
        if (!Pattern.compile( "[0-9]" ).matcher(password).find()) { // it doesn't contain any digit
            errors.reject("Password must have at least one digit");
        }
        if (password.toUpperCase().equals(password)) { //it's all upper-case
            errors.reject("Password must have at least one lower case character");
        }
        if (password.toLowerCase().equals(password)) { //it's all lower-case
            errors.reject("Password must have at least one upper case character");
        }
    }
}

When I pass in an invalid password/username, I get the following error:

java.lang.IllegalStateException: Could not resolve method parameter at index 0 in public org.springframework.http.ResponseEntity<com.myproject.project.core.controller.ExceptionResponse> com.myproject.project.core.controller.ExceptionHandlingController.invalidInput(java.lang.RuntimeException): No suitable resolver for argument 0 of type 'java.lang.RuntimeException'
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:175) ~[spring-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]

Why doesn't it catch MethodArgumentNotValidException?

2

1 Answer 1

1

At least, an exception MethodArgumentNotValidException is not a RuntimeException, but you use RuntimeException argument in that exception handler. For test change RuntimeException to Exception in method's argument.

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.