我获得了以下日志输出。我想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) {...}
答案 0 :(得分:9)
您需要一个用于ErrorMessage的序列化器。如果你使用eclipse Strg + Shift + T并搜索" JsonProcessingExceptionMapper"。此异常映射器希望使用实体ErrorMessage构建响应,但您没有此映射器。
您有两种选择:
选项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