Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ConstraintViolationException handler isn't executed in Micronaut

I have a ConstraintViolationException handler class that looks like this:

@Produces
@Singleton
@Requires(classes = {ConstraintViolationException.class, ExceptionHandler.class})
public class ConstraintsViolationsExceptionHandler
        implements ExceptionHandler<ConstraintViolationException, HttpResponse> {

    @Override
    public HttpResponse
    handle(HttpRequest request, ConstraintViolationException exception) {
        return HttpResponse
                .status(HttpStatus.FORBIDDEN)
                .contentType(MediaType.APPLICATION_JSON)
                .characterEncoding("UTF-8")
                .body(new SignUpPhoneNumberErrorResponse<>(400,
                        "Wrong data used",
                        new ArrayList<>(exception.getConstraintViolations())));
    }
}  

where SignUpPhoneNumberErrorResponse is my error handling POJO which is getting serialized to JSON absolutely fine.

My Controller looks like this:

@Controller(PhoneAuthAndLoginConstants.CONTROLLER_BASE_PATH)
@Validated
public class UserPhoneNumberRegistrationAndLoginController {

    @Inject
    MongoDbUserSignUpPhoneNumberDAO mongoDbUserSignUpPhoneNumberDAO;

    @Post(uri = PhoneAuthAndLoginConstants.CONTROLLER_SIGN_UP_PATH,
            consumes = MediaType.APPLICATION_JSON,
            produces = MediaType.APPLICATION_JSON)
    public Single<ResponseDataEncapsulate>
    signUpForPhoneVerification(@Valid @Body UserSignUpPhoneNumberEntity phoneNumber) {
        return mongoDbUserSignUpPhoneNumberDAO.sendVerification(phoneNumber);
    }

    @Post(uri = PhoneAuthAndLoginConstants.CONTROLLER_SIGN_UP_PATH
            +
            PhoneAuthAndLoginConstants.CONTROLLER_SIGN_UP_VERIFICATION_CODE_PARAM,
            consumes = MediaType.APPLICATION_JSON,
            produces = MediaType.APPLICATION_JSON)
    public Single<ResponseDataEncapsulate>
    sendUserSignUpConfirmation(@Valid @Body UserAccountStateSignUpEntity verificationData,
                               HttpHeaders httpHeaders) {
        return mongoDbUserSignUpPhoneNumberDAO.signUp(verificationData);
    }
}  

My POJO for UserAccountStateSignUpEntity looks like this:

@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class UserAccountStateSignUpEntity implements UserSignUpEntity {
    @NotNull @NotBlank @Size(min = 5, max = 13) private String phoneNumber;
    @NotNull @NotBlank @Size(min = 7, max = 7) private String verificationCode;
    @JsonIgnore private Boolean verifiedAccount = Boolean.FALSE;

    public UserAccountStateSignUpEntity(String phoneNumber, String verificationCode) {
        this.phoneNumber = phoneNumber;
        this.verificationCode = verificationCode;
        this.verifiedAccount = Boolean.TRUE;
    }

    @Override
    public Map<String, Object> makePhoneEntityMapForMongo() {
        HashMap<String, Object> returnMap = new HashMap<String, Object>() {{
            put("phoneNumber", phoneNumber);
            put("verificationCode", verificationCode);
            put("verifiedAccount", verifiedAccount);
        }};

        return Collections.unmodifiableMap(returnMap);
    }
}  

I send in a request payload like this:

{
    "phoneNumber" : "91-123456789",
    "verificationCode" : "18887"
}  

This should trigger a ConstraintViolationException and my handler code should execute and I should get a HTTP Forbidden. But instead I get the default HTTP Bad Request error message.

Why isn't my handler getting executed? What can be done to make it execute?

I'm using Micronaut 1.1.3 as the web framework and the Hibernate Validator as the javax.validation implementation.

like image 856
Shankha057 Avatar asked Jun 19 '19 22:06

Shankha057


3 Answers

@Error that can be applied to method to map it to an error route and SignUpPhoneNumberErrorResponse would be returned as a error response body when any ConstraintViolationException occured.

For more detail visit Micronaut docs

@Controller("/${path}")
@Validated
public class UserPhoneNumberRegistrationAndLoginController {

    @Post
    public HttpResponse method(@Valid @Body UserAccountStateSignUpEntity verificationData, HttpHeaders httpHeaders) {
        return null;
    }

    @Error(exception = ConstraintViolationException.class)
    public SignUpPhoneNumberErrorResponse onSavedFailed(HttpRequest request, ConstraintViolationException ex) {
        return new SignUpPhoneNumberErrorResponse(500,
                        "Wrong data used",
                        String.valueOf(ex.getConstraintViolations().stream().map( e -> e.getPropertyPath()+": "+e.getMessage()).collect(Collectors.toList())),
                "Application",
                "Error",
                System.currentTimeMillis());
    }

    @Error(status = HttpStatus.NOT_FOUND, global = true)  
    public HttpResponse notFound(HttpRequest request) {
        //return custom 404 error body
    }

} 
like image 182
2787184 Avatar answered Nov 12 '22 16:11

2787184


I recently had the same problem with error handling in Micronaut. As I figured out, there is not a org.hibernate.exception.ConstraintViolationException thrown, but a javax.persistence.PersistenceException.

For me, then it worked with @Error(exception = PersistenceException::class) (Kotlin).

like image 2
Roger Avatar answered Nov 12 '22 14:11

Roger


@Error annotation handling for ConstraintViolationException worked for me only when it is on controller.

In the end managed to handle it like this, by replacing the micronaut ConstraintExceptionHandler bean:

@Produces
@Replaces(io.micronaut.validation.exceptions.ConstraintExceptionHandler.class)
@Requires(classes = {ConstraintViolationException.class, ExceptionHandler.class})
public class ConstraintExceptionHandler extends io.micronaut.validation.exceptions.ConstraintExceptionHandler {

    @Override
    public HttpResponse handle(HttpRequest request, ConstraintViolationException exception) {
        return return HttpResponse
                .badRequest();
    }
}
like image 2
saganas Avatar answered Nov 12 '22 15:11

saganas