JAX-RS:抑制错误消息

JAX-RS : Suppress Error Message

我有一个 class,它采用像 Male,Female @POST 这样的枚举值。当我发送一个错误的值,如 'male' 而不是 'Male' 时,它会在 rest 客户端中显示 400 Bad Request 消息:Can not construct instance of constants.Constants$GenderEnum from String value 'male': value 不是声明的 Enum 实例名称之一 在[来源:org.apache.catalina.connector.CoyoteInputStream@718a453d;行:7,列:23](通过引用链:valueobjects.ConsumerValueObject["gender"])

我的休息终点如下所示:

@Consumes("application/json")
@Produces("application/json")
@POST
public Response addConsumer(ConsumerValueObject consumerVO)

此处 ConsumerValueObject 包含枚举。

如何在 Rest 客户端中抑制该错误消息?我尝试使用 ExceptionMapper,但它没有帮助!由于安全问题,我需要禁止显示消息!

您真的要取消错误消息还是要修复实际的问题?

您实际上可以使用像

这样的自定义异常映射器捕获所有抛出的异常
@Provider
public class CustomExceptionMapper implements ExceptionMapper<Throwable> {
    @Override
    public Response toResponse(Throwable t) {
        return Response.ok().build();
    }
}

尽管如此,这将处理所有捕获的异常和 return 一个 200 OK 欺骗客户认为请求实际上成功了 - 但事实并非如此!除了 Throwable 之外,您还应该能够捕获具体的异常(即使它是 RuntimeException)——也许您没有将其声明为提供者或没有指定正确的异常 class?

不过,正如已经提到的,return为异常设置不同的状态代码通常是不好的做法,应该避免。在这种情况下,解决实际问题可能更合适。

JAX-RS 提供 MessageBodyReaderMessageBodyWriter 接口,您可以声明 un/marshall 对象的输入流或 return 输出流的对象.官方documentation on MessageBodyReader在这方面有更详细的信息。

因此,一个实现可以是以下步骤:

  • 读取输入流到 f.e。字符串
  • 用大写版本替换所有 "male""female" 标记
  • 将字符串解析为 json 表示(使用 org.json.JSONObject f.e)
  • 使用 ObjectMapper 将 JSON 表示转换为 Java 对象
  • return映射对象

如果输入失败只是一个简单的 upper/lower 案例问题,这将起作用。如果有拼写错误或语义替代可用,但您的枚举中还没有,您需要付出更多努力。

但是,如果您未能创建正确的对象表示,您应该 return 向客户端发送用户故障(在 400 范围内)以通知客户端出现问题。

这是 JsonParseExceptionMapper or JsonMappingExceptionMapper 对杰克逊的回应。这些 classes 带有依赖性

<dependency>
  <groupId>com.fasterxml.jackson.jaxrs</groupId>
  <artifactId>jackson-jaxrs-json-provider</artifactId>
  <version>${2.x.version}</version>
</dependency>

无论您有这种显式依赖还是有 resteasy-jackson2-provider(它在幕后使用上述内容),映射器很可能是通过 class 路径扫描隐式注册的。例如你有一个空的 Application class.

@ApplicationPath("/")
public class ResteasyApplication extends Application {}

这将导致 disovery/registration 通过 class 路径扫描。如果您没有这些依赖项中的任何一个,并且如果您在 Wildfly 中,我不确定它们是如何注册的,但这就是正在发生的事情。

您可以 write/register 您自己的 ExceptionMappers JsonParseExceptionJsonMappingException

@Provider
public class JsonMappingExceptionMapper 
             implements ExceptionMapper<JsonMappingException> {
    
    @Override
    public Response toResponse(JsonMappingException e) {
        return Response.status(Response.Status.BAD_REQUEST).build();
    } 
}

但根据我的测试,要注册哪一个,你的还是杰克逊的,这是一个折腾。映射器被放入一个集合(如此无序),然后被推入一个地图,所以只有一个被推入。他们被推入的顺序就像我说的那样是一个折腾。

我想这实际上只是部分答案,因为除了显式注册所有 classes(最终 ),但这很麻烦。

不过现在战局缩小了。以后有机会我会再试一次


更新

所以这不是一个解决方案,只是一个半概念验证来展示我们如何让它使用我们的 ExceptionMapper。

import org.jboss.resteasy.spi.ResteasyProviderFactory;
import com.fasterxml.jackson.databind.JsonMappingException;

import com.my.pkg.JsonMappingExceptionMapper;

@Path("/init")
public class InitResource {
    
    @GET
    public Response init() {
        ResteasyProviderFactory factory = ResteasyProviderFactory.getInstance();
        factory.getExceptionMappers().put(JsonMappingException.class, 
                                          new JsonMappingExceptionMapper());
        return Response.ok("Done!").build();
    }
}

一旦我们第一次到达 init 端点,我们的 JsonMappingExcpetionMapper 将注册并覆盖现有的,无论是 Jackson 的还是我们的。

当然我们不想真的这样做,它只是展示如何覆盖映射器。我不知道该把这段代码放在哪里。我在 Application 构造函数中尝试了一个 ServletContextListener,在一个低优先级的 Feature 中。我想不通。 None 以上发生在 RESTeasy 最终注册之前。