Dropwizard error messages from Jersey

You need a serialiszer for ErrorMessage. If you use eclipse Strg+Shift+T and search for "JsonProcessingExceptionMapper". This Exception mapper wants to build response with entity ErrorMessage, but you have no mapper for this.

You have two options:

  1. Remove this exception mapper and add your custom exception mapper with no entity
  2. You create a message body writer.

Option 1: add this method in your run():

private void removeDefaultExceptionMappers(boolean deleteDefault,Environment environment)
{
    if(deleteDefault){
        ResourceConfig jrConfig = environment.jersey().getResourceConfig();
        Set<Object> dwSingletons = jrConfig.getSingletons();
        List<Object> singletonsToRemove = new ArrayList<Object>();

        for (Object singletons : dwSingletons) {
            if (singletons instanceof ExceptionMapper && !singletons.getClass().getName().contains("DropwizardResourceConfig")) {
                singletonsToRemove.add(singletons);
            }
        }

        for (Object singletons : singletonsToRemove) {
            LOG.info("Deleting this ExceptionMapper: " + singletons.getClass().getName());
            jrConfig.getSingletons().remove(singletons);
        }
    }
}

This removes all exeption mappers added by default in DW. Now you can add all exeption mappers you really want. In my case:

    environment.jersey().register(new ConstraintViolationExceptionMapper());
    environment.jersey().register(new CustomJsonProcessingExceptionMapper());
    environment.jersey().register(new EarlyEofExceptionMapper());

Now write your own custom CustomJsonProcessingExceptionMapper without entity:

@Provider
public class CustomJsonProcessingExceptionMapper implements ExceptionMapper<JsonProcessingException> {

    private static final Logger LOG = LoggerFactory.getLogger(CustomJsonProcessingExceptionMapper.class);

    @Override
    public Response toResponse(JsonProcessingException exception) {
        /*
         * If the error is in the JSON generation, it's a server error.
         */
        if (exception instanceof JsonGenerationException) {
            LOG.warn("Error generating JSON", exception);
            return Response.serverError().build();
        }

        final String message = exception.getOriginalMessage();

        /*
         * If we can't deserialize the JSON because someone forgot a no-arg constructor, it's a
         * server error and we should inform the developer.
         */
        if (message.startsWith("No suitable constructor found")) {
            LOG.error("Unable to deserialize the specific type", exception);
            return Response.serverError().build();
        }

        /*
         * Otherwise, it's those pesky users.
         */
        LOG.debug("Unable to process JSON (those pesky users...)", exception);
        return Response.status(Response.Status.BAD_REQUEST)
                       .build();
    }

}

Option 2: You create an serializer/message body writer for ErrorMessage. To do so try this:

@Provider
@Produces(MediaType.TEXT_PLAIN)
public class ErrorMessageBodyWriter implements MessageBodyWriter<ErrorMessage> {

    private static final Logger LOG = LoggerFactory.getLogger(ErrorMessageBodyWriter.class);

    @Override
    public boolean isWriteable(
        Class<?> type,
        Type genericType,
        Annotation[] annotations,
        MediaType mediaType)
    {
        return ValidationErrorMessage.class.isAssignableFrom(type);
    }

    @Override
    public long getSize(
        ErrorMessage t,
        Class<?> type,
        Type genericType,
        Annotation[] annotations,
        MediaType mediaType)
    {
        return -1;
    }

    @Override
    public void writeTo(
        ErrorMessage t,
        Class<?> type,
        Type genericType,
        Annotation[] annotations,
        MediaType mediaType,
        MultivaluedMap<String, Object> httpHeaders,
        OutputStream entityStream) throws IOException, WebApplicationException
    {       
        String message = t.getMessage();        
        entityStream.write(message.getBytes(Charsets.UTF_8));
        LOG.info(message);
    }

}

Add in your run():

// Serializer
environment.jersey().register(new ErrorMessageBodyWriter());    

Hope this helps :-)


Just need to specify these headers for your resource so that dropwizard understands which error message builder to use for the response:

@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)

Dropwizard will log the underlying error at DEBUG level, so you can turn that on in your logging config to see the cause here:

io.dropwizard.jersey.jackson.JsonProcessingExceptionMapper: DEBUG