我使用Jersey向外部世界提供java REST服务。我提供了一些接受JSON的函数,并结合使用Jackson框架和jersey将它们转换为pojo。
我有一个问题,如果错误的杰克逊格式被发送到服务器,答案(http响应的内容)是一个杰克逊特定的异常描述。如果我有一个带有属性"姓氏"的POJO,并将json字符串中的"姓氏"发送到服务器,我得到:
Unrecognized field "sursname" (Class XY), not marked as ignorable at [Source: sun.net.httpserver.FixedLengthInputStream@903025; line: 1, column: 49] (through reference chain: XY["sursname"])
这很好,但我想有我自己的响应内容,例如我自己的错误代码。我已经编写了一个自定义ExceptionMapper,它应该映射所有Throwables。
@Provider
public class WebserviceExceptionMapper implements ExceptionMapper<Throwable> {
@Override
public Response toResponse(Exception e) {
e.printStackTrace();
return Response.status(400).entity("{"errorcode":"CRITICAL_ERROR"}").type(MediaType.APPLICATION_JSON).build();
}
}
似乎在我的webservice方法被调用之前抛出了jackson异常,所以我没有机会映射它?
有人有什么想法吗?非常感谢,很抱歉我的英语;)
您的自定义ExceptionMapper不能捕获异常的原因是因为Jackson库提供了自己的异常映射器,它在常规异常映射器捕获异常之前捕获异常。
有人建议你应该为JsonParseExceptionMapper和JacksonMappingExceptionMapper实现你自己的异常映射器,但是,这会给出不一致的结果。在他们的GitHub上查看这个问题。
要解决这个问题,必须确保没有注册任何内置异常映射器。如果您正在使用JSON: jackson-jaxrs-json-provider的库,请确保您只在中注册JacksonJaxbJsonProvider.class或JacksonJsonProvider.class应用程序类:
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(JacksonJaxbJsonProvider.class)
}
}
注意JacksonFeature.class,因为它注册了内置的ExceptionMappers。还要远离jersey-media-json-jackson库,它会自动添加一些内置的异常映射器,而无需您做任何事情。
我在使用Jackson和Apache CXF时遇到了类似的问题。如果异常没有发生在我的JAX-RS方法中,而是发生在JacksonJsonProvider
中,则不会调用异常映射器。在我的情况下,解决方案是扩展JacksonJsonProvider
,捕获特定的Jackson json异常,并将它们作为WebApplicationException
重新抛出。
这是我为扩展的JacksonJsonProvider
重写的readFrom方法:
@Override
public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException {
try {
return super.readFrom(type, genericType, annotations, mediaType, httpHeaders, entityStream);
} catch (JsonParseException jpe) {
throw new WebApplicationException(jpe, Response.status(Status.BAD_REQUEST)
.entity(new ErrorEntity("Malformed json passed to server: n" + jpe.getMessage())).build());
} catch (JsonMappingException jme) {
throw new WebApplicationException(jme, Response
.status(Status.BAD_REQUEST)
.entity(new ErrorEntity("Malformed json passed to server, incorrect data type used: n"
+ jme.getMessage())).build());
}
}
当然在此之前会抛出Jackson异常:调用Jackson提供程序是为了在方法中创建您期望的对象。但是,使用ExceptionMapper,您不仅可以映射异常,还可以映射提供者异常。
您确定您的提供者已注册吗?它被调用,如果你抛出异常从你的方法,而不是从提供程序?
如果上一个问题的答案是"是",尝试为一个具体的异常实现ExceptionMapper,而不是Throwable。
我遇到了同样的问题并解决了覆盖ExceptionMapper的问题。完美!我需要做的另一件事是,我不理解100%是如何覆盖我的应用程序的JacksonProvider(我不知道它是否与我使用的Jersey的版本有关- 2.19)。下面是覆盖它的web.xml部分:
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider
</param-value>
感谢您的帮助,JsonParseException的ExceptionMapper没有帮助。我从我的项目中删除了jackson jar文件,并包含了jackson源代码。然后我修改了ord.codehaus.jackson.jaxrs.JsonParseExceptionMapper和JacksonMappingExceptionMapper,以返回我的自定义响应内容。我对它不满意,但它现在好用了!
谢谢你的帮助!