泽西异常映射器在杰克逊反序列化失败时不起作用

2022-09-02 11:55:17

我在我的 REST API 中使用 Jersey 2.10 和 Jackson 序列化/反序列化功能。

我的想法是让我的 REST API 始终返回标准的 JSON 错误响应。为此,我有 ExceptionMapper 类,它们为 Jersey 应用程序中引发的任何异常构建正确的 json 错误响应。我还有一个jsp,它产生相同类型的JSON响应,我在Web中将其注册为错误页面.xml它涵盖了在加载泽西岛之前可能出现的所有错误。

但是有一种情况下,我的异常映射器和我的json生成jsp都没有工作,那就是当将一个格式错误的json发送到POST REST端点时,它只返回以下消息:

HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, DELETE, PUT
Content-Type: text/plain
Content-Length: 210
Date: Tue, 24 Jun 2014 22:14:11 GMT
Connection: close

Can not deserialize instance of com.example.rest.User[] out of START_OBJECT token
 at [Source: org.glassfish.jersey.message.internal.EntityInputStream@1dcccac; line: 1, column: 1]

如何使 Jersey 返回我的自定义错误响应而不是此响应?

更新:

根据@Lucasz的答案,我做了更多的研究,发现在软件包中定义了两个异常映射器 com.fasterxml.jackson.jaxrs.base (https://github.com/FasterXML/jackson-jaxrs-providers/tree/master/base/src/main/java/com/fasterxml/jackson/jaxrs/base) JsonMappingExceptionMapper 和 JsonParseExceptionMapper,它们似乎在阴影我的自定义映射器。

如何注销这些映射器?

这就是我当前注册映射器的方式:

@ApplicationPath("/")
public class MyApp extends ResourceConfig{
    public SyntheticAPIApp() {
        packages("com.example.resource", "com.example.mapper");
        register(org.glassfish.jersey.jackson.JacksonFeature.class);
    }
}

答案 1

我用异常映射器测试了它,如下所示:

import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

import com.fasterxml.jackson.core.JsonProcessingException;

@Provider
public class JsonProcessingExceptionMapper implements ExceptionMapper<JsonProcessingException>{

        public static class Error {
            public String key;
            public String message;
        }

        @Override
        public Response toResponse(JsonProcessingException exception) {
            Error error = new Error();
            error.key = "bad-json";
            error.message = exception.getMessage();
            return Response.status(Status.BAD_REQUEST).entity(error).build();
        }
}

它奏效了。


更新:将JsonParseException更改为JsonProcessingException(更通用)


更新2:为了避免注册不需要的映射器替换

register(org.glassfish.jersey.jackson.JacksonFeature.class);

register(com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider.class);

看看JacksonFeature的源代码,你就会明白发生了什么。


答案 2

从泽西岛 2.26 (12) 开始,使用足够高的自定义异常映射器进行注释应该就足够了(此处表示低的严格正数)。要覆盖 (to ) 提供的“默认”映射器,我们只提供以下两个自定义映射器:Priorityorg.glassfish.jersey.media:jersey-media-json-jacksonregister(JacksonFeature.class)

@Provider
@Priority(1)
public class JsonMappingExceptionMapper implements ExceptionMapper<JsonMappingException> {
  /* ... */
}
@Provider
@Priority(1)
public class JsonParseExceptionMapper implements ExceptionMapper<JsonParseException> {
  /* ... */
}

不幸的是,JAX-RS 2 规范忽略了优先级,只声明:

选择异常映射提供程序来映射异常时,实现必须使用泛型类型为异常最接近的超类的提供程序。

没有像另一个答案中提到的那样注册和注册并没有导致一致的结果。JacksonFeature.classJacksonJaxbJsonProvider.class