Jersey的自定义ExceptionMapper不适用于无效的JSON输入

时间:2016-11-07 17:59:12

标签: json jersey jackson jax-rs

我有以下资源使用JSON映射到POJO。

@Path("example")
public class ExampleResource {

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response addThesis(MyObject myObject) {
        return Response.ok().entity("Test").build();
    }
}

这是POJO课程:

public class MyObject {
    private String title;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}

当我发送一个POST请求时,身体 {"标题":"测试标题"} 一切正常。正如预期的那样,响应是测试。但是,当我将请求更改为 {" titlee":"测试标题"} 时,服务器会回复:

  

无法识别的字段" titlee" (类com.my.package.MyObject),未标记为可忽略(一个已知属性:" title"])    在[来源:org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@6dc6a46a; line:2,column:11](通过引用链:com.my.package.MyObject [" titlee"])

显然这是泽西投掷并退回的例外。如何拦截此异常并返回自定义状态代码和消息?

到目前为止,我所尝试的是实现自己的ExceptionMapper:

@Provider
public class MyJsonExceptionMapper implements ExceptionMapper<JsonProcessingException> {
    public Response toResponse(JsonProcessingException e) {
        return Response.status(400).entity("JSON Processing Error").build();
    }
}

不幸的是,响应保持不变。当我为自定义异常实现ExceptionMapper并在资源方法中抛出相应的异常时,一切正常。我假设这与JsonProcessingException的默认ExceptionMapper有关,它覆盖了我自己的。然后我尝试创建一个通用映射器(&#34;实现ExceptionMapper&#34;),但再次没有成功。

我到处都看了很多东西并尝试了很多东西,包括扩展ResourceConfig和注册我的mapper,但到目前为止还没有任何工作。

可能有助于缩小问题范围的更多信息:我使用Grizzly2作为HTTP服务器,我将其部署为Fat JAR。

我的pom.xml的依赖部分如下所示:

<dependencies>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>2.24</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-grizzly2-http</artifactId>
        <version>2.24</version>
    </dependency>
</dependencies>

非常感谢任何建议。

3 个答案:

答案 0 :(得分:5)

好吧,这是愚蠢和黑客,但对我有用:

register(JacksonJaxbJsonProvider.class);

这是由于Jackson功能入口点中的以下“不错的默认行为”:

if (!config.isRegistered(JacksonJaxbJsonProvider.class)) { // add the default Jackson exception mappers context.register(JsonParseExceptionMapper.class); context.register(JsonMappingExceptionMapper.class);

:(

但是,我仍然更喜欢能够解决“真实”问题的答案 - 即。没有预先注册组件,以便该功能无法正确配置...

答案 1 :(得分:3)

我也遇到过这个问题。如果注册了JacksonFeature,您只需注册JacksonJaxbJsonProvider即可解决此问题。

JacksonFeature位于类路径中时,Jersey会自动发现它。另一种解决方法是将ServerProperties.FEATURE_AUTO_DISCOVERY_DISABLE设置为true来禁用自动发现功能。因此,您需要手动注册其他功能。

或者,您可以删除jersey-media-json-jackson工件并改为使用jackson-jaxrs-json-provider。有了这个,你将摆脱JacksonFeature,然后你可以注册自己的异常映射器。

最后一个选项,也许似乎是正确的解决方案(如Kysil Ivan的answer中指出的那样),您可以编写自己的异常映射器,然后给它一个高优先级,例如为1。如果您使用自动发现,只需使用@Provider@Priority注释:

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

如果您手动注册提供商,可以give your provider a binding priority

@ApplicationPath("/")
public class MyResourceConfig extends ResourceConfig {

    public MyResourceConfig() {
        register(JsonParseExceptionMapper.class, 1);
    }
}

有关详细信息,请参阅此answer

答案 2 :(得分:0)

我们在Wildfly上使用JAX-RS来实现我们的Web服务,并使用以下内容来完成您在Glassfish上使用Jersey所做的事情。也许它有类似的功能,你可以查找。我们的步骤是:

  • 该服务是无状态EJB,使用EJB拦截器来捕获异常 并使用详细信息填充请求范围对象
  • 实现一个PostProcessInterceptor,它从请求范围对象中读取并在服务返回之前修改响应。 (这是JAX-RS特有的)