来自泽西岛的Dropwizard错误消息

时间:2014-10-01 09:46:04

标签: error-handling jersey jax-rs dropwizard

我获得了以下日志输出。我想drop向导试图错误,但它使用的Jersey JAX-RS实现并不知道如何格式化错误?我怎么看?

ERROR [2014-10-01 08:08:55,875] com.sun.jersey.spi.container.ContainerResponse: A message body writer for Java class io.dropwizard.jersey.errors.ErrorMessage, and Java type class io.dropwizard.jersey.errors.ErrorMessage, and MIME media type text/plain was not found.
The registered message body writers compatible with the MIME media type are:
*/* ->
  com.sun.jersey.core.impl.provider.entity.FormProvider
  com.sun.jersey.core.impl.provider.entity.StringProvider
  com.sun.jersey.core.impl.provider.entity.ByteArrayProvider
  com.sun.jersey.core.impl.provider.entity.FileProvider
  com.sun.jersey.core.impl.provider.entity.InputStreamProvider
  com.sun.jersey.core.impl.provider.entity.DataSourceProvider
  com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$General
  com.sun.jersey.core.impl.provider.entity.ReaderProvider
  com.sun.jersey.core.impl.provider.entity.DocumentProvider
  com.sun.jersey.core.impl.provider.entity.StreamingOutputProvider
  com.sun.jersey.core.impl.provider.entity.SourceProvider$SourceWriter
  com.sun.jersey.server.impl.template.ViewableMessageBodyWriter
  com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$General
  com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$General
  com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider
text/plain ->
  com.sun.jersey.core.impl.provider.entity.StringProvider
  com.sun.jersey.core.impl.provider.entity.ReaderProvider

FWIW方法签名我打的是:

@POST
@UnitOfWork
@Path("/update")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.TEXT_PLAIN)
public String updateResults(ResultsUpdate results) {...}

5 个答案:

答案 0 :(得分:9)

您需要一个用于ErrorMessage的序列化器。如果你使用eclipse Strg + Shift + T并搜索" JsonProcessingExceptionMapper"。此异常映射器希望使用实体ErrorMessage构建响应,但您没有此映射器。

您有两种选择:

  1. 删除此异常映射器并添加自定义异常映射器 没有实体
  2. 您创建了一个邮件正文撰稿人。
  3. 选项1: 在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);
            }
        }
    }
    

    这将删除DW中默认添加的所有exeption映射器。现在您可以添加您真正想要的所有exeption映射器。就我而言:

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

    现在编写自己的自定义CustomJsonProcessingExceptionMapper,不带实体:

    @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();
        }
    
    }
    

    选项2: 您为ErrorMessage创建序列化程序/消息正文编写器。为此,试试这个:

    @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);
        }
    
    }
    

    添加你的run():

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

    希望这会有所帮助: - )

答案 1 :(得分:5)

只需为您的资源指定这些标头,以便dropwizard了解用于响应的错误消息构建器:

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

答案 2 :(得分:3)

Dropwizard会在DEBUG级别记录底层错误,因此您可以在日志配置中启用它以查看原因:

io.dropwizard.jersey.jackson.JsonProcessingExceptionMapper: DEBUG

答案 3 :(得分:2)

这很愚蠢,但是我点击了一个dropwizard从一个主类运行,所以你可以在ErrorMessage中放一个断点并在Eclipse中运行它。

顺便提一下,这种情况下的潜在错误是:

Can not deserialize instance of java.util.ArrayList out of START_OBJECT token

答案 4 :(得分:1)

我最近几次打了这个,所以提交了一个(现在接受的)pull请求来记录警告而不是调试的基础错误。

https://github.com/dropwizard/dropwizard/commit/ebdfcb47a030730233cf0984aadae155ec138ff3