Search code examples
javajacksonjettydropwizardexceptionmapper

Dropwizard deserialising custom exception as JSON?


I have created a new exception class in my Dropwizard service that extends BadRequestException.

public class CustomBadRequestException extends BadRequestException {

    private static final long serialVersionUID = 1L;

    private List<ValidationFailureDto> validationFailures;

    public CustomBadRequestException() {
        super();
    }

    public CustomBadRequestException(final List<ValidationFailureDto> validationFailures) {
        super();
        this.validationFailures = validationFailures;
    }

    @ApiModelProperty(value = "List of validationFailures")
    public List<ValidationFailureDto> getValidationFailures() {
        return validationFailures;
    }
}

When I throw that exception at first I was only getting back the deserialised BadRequestException, minus the additional property (validationFailures)

{
code: "400",
message: "Bad request"
}

This is because Dropwizard's internals have a default exception mapper that allows Jetty/Jackson to understand domain exceptions and how to send the appropriate HTTP response.

To overcome this you can implement your own ExceptionMapper class and register it with Dropwizard.

public class CustomBadRequestExceptionMapper implements ExceptionMapper<SamplePackOrderBadRequestException> {

/**
 * Allows jackson to deserialise custom exceptions and its properties to JSON response
 *
 * @param exception exception
 * @return response object
 */
@Override
public Response toResponse(final SamplePackOrderBadRequestException exception) {

    if (exception instanceof SamplePackOrderBadRequestException) {

        SamplePackOrderBadRequestException samplePackOrderBadRequestException
                = (SamplePackOrderBadRequestException) exception;
        return Response
                .status(400)
                .entity(samplePackOrderBadRequestException)
                .build();
    }
    return Response.status(400).build();
}
}

However this issue with this is that it deserializes super (Throwable), so you get every single inherited property added in the response which I do not want.

To combat this I tried adding Jackson annotations like so:

@JsonIgnoreProperties(value = "stackTrace")

This is not an optimal solution as there are several properties other than stackTrace that I will need to ignore.

So to summarise, how can I get Dropwizard to properly deserialize my CustomException class without all the additional clutter that I do not need?


Solution

  • I think the easier option is to transform exception to a Error bean and return it as shown below.

    public class CustomBadRequestExceptionMapper implements ExceptionMapper<SamplePackOrderBadRequestException> {
    
    
    @Override
    public Response toResponse(final SamplePackOrderBadRequestException exception) {
    
        if (exception instanceof SamplePackOrderBadRequestException) {
    
            SamplePackOrderBadRequestException ex
                = (SamplePackOrderBadRequestException) exception;
             return Response
                .status(400)
                .entity(new ErrorBean(400,ex.getMessage,ex.getgetValidationFailures()))
                .build();
        }
        return Response.status(400).build();
    }
    }
    

    And ErrorBean.java

        public static class ErrorBean{
        private int code;
        private String message;
        private List<ValidationFailureDto> failures;
        public int getCode() {
            return code;
        }
        public void setCode(int code) {
            this.code = code;
        }
        public String getMessage() {
            return message;
        }
        public void setMessage(String message) {
            this.message = message;
        }
        public List<ValidationFailureDto> getFailures() {
            return failures;
        }
        public void setFailures(List<ValidationFailureDto> failures) {
            this.failures = failures;
        }
    }