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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24397647/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 11:58:30  来源:igfitidea点击:

Jersey Exception mappers not working when Hymanson deserialization fails

javarestjerseyHymanson

提问by raspacorp

I am using Jersey 2.10 with Hymanson serialization/deserialization feature in my REST API.

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

My idea is to make my REST API to always return a standard JSON error response. For that I have ExceptionMapper classes that build proper json error responses for any exception being thrown in the Jersey application. I also have a jsp which produces the same kind of JSON response, which I registered as error-page in the web.xml that covers all the errors that could come before Jersey being loaded.

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

But there is one case in which neither my Exception mappers nor my json producing jsp are working, that is when sending a bad formed json to a POST REST endpoint which just returns the following message:

但是在一种情况下,我的异常映射器和我的 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]

How can I make Jersey to return my custom error response instead of this?

我怎样才能让 Jersey 返回我的自定义错误响应而不是这个?

UPDATE:

更新:

Based on the answer by @Lucasz, I did more research and found that there are two Exception mappers defined inside the package com.fasterxml.Hymanson.jaxrs.base (https://github.com/FasterXML/Hymanson-jaxrs-providers/tree/master/base/src/main/java/com/fasterxml/Hymanson/jaxrs/base) JsonMappingExceptionMapper and JsonParseExceptionMapper that seem to be shadowing my custom mappers.

根据@Lucasz 的回答,我做了更多的研究,发现在包 com.fasterxml.Hymanson.jaxrs.base ( https://github.com/FasterXML/Hymanson-jaxrs-providers/ tree/master/base/src/main/java/com/fasterxml/Hymanson/jaxrs/base) JsonMappingExceptionMapper 和 JsonParseExceptionMapper 似乎掩盖了我的自定义映射器。

How can I unregister those mappers?

如何取消注册这些映射器?

This is how I am currently registering the mappers:

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

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

采纳答案by Lukasz Wiktor

I tested it with an exception mapper like below:

我使用如下异常映射器对其进行了测试:

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.Hymanson.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();
        }
}

and it worked.

它奏效了。



Update:changed JsonParseException to JsonProcessingException (more general)

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



Update2:In order to avoid registering the unwanted mappers replace

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

register(org.glassfish.jersey.Hymanson.HymansonFeature.class);

with

register(com.fasterxml.Hymanson.jaxrs.json.HymansonJaxbJsonProvider.class);

Look at the source code of HymansonFeatureand you'll understand what's happening.

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

回答by David Georg Reichelt

I had the same problem, and the previous answer led me to the solution, but was not forking for me current Jersey (2.22). At first, I needed to use the org.glassfish.jersey.spi.ExtendedExceptionMapperlike described in https://jersey.java.net/documentation/latest/representations.html.

我遇到了同样的问题,之前的答案让我找到了解决方案,但并没有为我当前的泽西岛(2.22)分叉。起初,我需要使用https://jersey.java.net/documentation/latest/representations.html 中org.glassfish.jersey.spi.ExtendedExceptionMapper描述的类似内容。

Furthermore, Jersey is checking for an exception mapper, which is as close as possible to the thrown exception (from org.glassfish.jersey.internal.ExceptionMapperFactory):

此外,Jersey 正在检查异常映射器,它尽可能接近抛出的异常(来自org.glassfish.jersey.internal.ExceptionMapperFactory):

for (final ExceptionMapperType mapperType : exceptionMapperTypes) {
        final int d = distance(type, mapperType.exceptionType);
        if (d >= 0 && d <= minDistance) {
            final ExceptionMapper<T> candidate = mapperType.mapper.getService();

            if (isPreferredCandidate(exceptionInstance, candidate, d == minDistance)) {
                mapper = candidate;
                minDistance = d;
                if (d == 0) {
                    // slight optimization: if the distance is 0, it is already the best case, so we can exit
                    return mapper;
                }
            }
        }
    }

Therefore I needed to map exactly the exception and not a more general exception.

因此,我需要准确地映射异常而不是更一般的异常。

In the end, my provider looks as follows:

最后,我的提供者如下所示:

@Provider
public final class JsonParseExceptionExceptionHandler implements ExtendedExceptionMapper<JsonParseException> {
    @Override
    public Response toResponse(final JsonParseException exception) {
        exception.printStackTrace();
        return Response.status(Response.Status.BAD_REQUEST).entity("JSON nicht in korrektem Format.").build();
    }

    @Override
    public boolean isMappable(final JsonParseException arg0) {
        return true;
    }
}

回答by heronsanches

I used "Hymanson-jaxrs-json-provider 2.8.8" and JAX-RS 2.0

我使用了“Hymanson-jaxrs-json-provider 2.8.8”和JAX-RS 2.0

Application class - you needs to register your ExceptionMapper implementation class:

应用程序类 - 您需要注册您的 ExceptionMapper 实现类:

@ApplicationPath("pathApplication")
public class ApplicationConfiguration extends Application{


   @Override
   public Set<Class<?>> getClasses() {

      Set<Class<?>> resources = new HashSet<>();
      resources.add(YourJAXRSClass.class);
      resources.add(JsonHymansonEM.class); //ExceptionMapper class implementation
      //others resources that you need...
      return resources; 

   }


}

ExceptionMapper class implementation:

ExceptionMapper 类实现:

@Provider
public class JsonHymansonEM implements ExceptionMapper<JsonParseException>{


   @Override
   public Response toResponse(JsonParseException exception) {
      //you can return a Response in the way that you want!
      return Response.ok(new YourObject()).build();
   }


}

回答by Mateus Costa

I had the same problem and solve overriding the ExceptionMapper. Perfect! One extra thing that I needed to do and were not understanding 100% was how to override the HymansonProvider for my application (I don't know if it was related to Jersey's version that I was using - 2.19). Here's my web.xml part that overrides it:

我遇到了同样的问题并解决了覆盖 ExceptionMapper 的问题。完美的!我需要做的另一件事是如何覆盖我的应用程序的 HymansonProvider(我不知道它是否与我使用的 Jersey 版本 - 2.19 相关)。这是我覆盖它的 web.xml 部分:

<init-param>
    <param-name>jersey.config.server.provider.classnames</param-name>
       <param-value>
          com.fasterxml.Hymanson.jaxrs.json.HymansonJaxbJsonProvider
       </param-value>
</init-param>

回答by René

Starting with Jersey 2.26 (1, 2) it should be enough to annotate the custom exception mapper with a sufficiently high Priority(highhere meaning a low, strictly positive number). To override the “default” mappers provided by org.glassfish.jersey.media:jersey-media-json-Hymanson(to register(HymansonFeature.class)) we only provide these two custom mappers:

从 Jersey 2.26 ( 1, 2)开始,用足够高的值来注释自定义异常映射器就足够了Priority(这里的意味着低,严格的正数)。要覆盖org.glassfish.jersey.media:jersey-media-json-Hymanson(to register(HymansonFeature.class))提供的“默认”映射器,我们只提供这两个自定义映射器:

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

Unfortunately JAX-RS 2 Spec disregards priorities and only states:

不幸的是,JAX-RS 2 规范无视优先级,仅声明:

When choosing an exception mapping provider to map an exception, an implementation MUST use the provider whose generic type is the nearest superclass of the exception.

选择异常映射提供程序以映射异常时,实现必须使用通用类型是异常的最近超级类的提供程序。

Not registering HymansonFeature.classand registering HymansonJaxbJsonProvider.classinstead as mentioned in another answer did not lead to consistent results.

如另一个答案中所述,不注册HymansonFeature.class和注册HymansonJaxbJsonProvider.class并没有导致一致的结果。