Jersey/Jackson例外问题与ExceptionMapper



我使用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.classJacksonJsonProvider.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,以返回我的自定义响应内容。我对它不满意,但它现在好用了!

谢谢你的帮助!

最新更新