JAX-RS:抑制错误消息

时间:2015-07-16 10:52:35

标签: java rest enums jax-rs resteasy

我有一个类,它接受像男性,女性@POST这样的枚举值。当我发送一个错误的值,如'male'而不是'Male'时,它会在休息客户端显示400 Bad Request with this message: 无法构造constants.Constants $ GenderEnum from String value'male' :value不是声明的Enum实例名称之一  在[来源:org.apache.catalina.connector.CoyoteInputStream@718a453d; line:7,column:23](通过引用链:valueobjects.ConsumerValueObject [“gender”])

我的休息终点如下所示:

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

这里ConsumerValueObject包含枚举。

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

2 个答案:

答案 0 :(得分:1)

你真的想要压制错误信息,还是想修复实际的问题?

您实际上可以使用自定义异常映射器(如

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

但是,这将处理所有捕获的异常并返回200 OK,这会诱使客户认为请求实际成功 - 事实并非如此!而不是Throwable你应该能够捕获具体的异常(即使它是一个RuntimeException) - 也许你没有将它声明为提供者或者没有指定正确的异常类?

尽管如前所述,为异常返回不同的状态代码通常是不好的做法,应该避免。在这种情况下,修复实际问题可能更合适。

JAX-RS提供MessageBodyReaderMessageBodyWriter接口,您可以声明这些接口取消/编组对象或对象的输入流以返回到输出流。官方documentation on MessageBodyReader提供了有关这方面的更详细信息。

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

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

如果输入失败只是一个简单的大/小写问题,这是有效的。如果有错字或语义替代可用,但尚未在你的枚举中,你需要付出更多的努力。

但是,如果您无法创建正确的对象表示,则应将用户失败(400范围内的某些内容)返回给客户端,以通知客户端出现了问题。

答案 1 :(得分:1)

这是杰克逊对JsonParseExceptionMapperJsonMappingExceptionMapper的回应。这些类带有依赖

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

无论您是否具有此显式依赖关系,或者您拥有resteasy-jackson2-provider(使用上面的内容),很可能是通过类路径扫描隐式注册映射器。例如,您有一个空的Application类。

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

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

您可以为ExceptionMappersJsonParseException

撰写/注册自己的JsonMappingException
@Provider
public class JsonMappingExceptionMapper 
             implements ExceptionMapper<JsonMappingException> {

    @Override
    public Response toResponse(JsonMappingException e) {
        return Response.status(Response.Status.BAD_REQUEST).build();
    } 
}

但是从我测试的内容来看,它是一个关于注册哪个,你的或杰克逊的翻版。映射器被放入一个Set(如此无序),然后被推入一个Map,所以只有一个得到了推进。按照我说的推进它们的顺序是一个折腾。

我想这实际上只是一个部分答案,因为除了明确注册所有类(最终disabling the classpath scanning)之外,我还没有找到保证使用你的mapper的解决方案,但那是麻烦。

但现在战斗已经缩小了。如果我以后有机会,我会再试一次

更新

所以这不是一个解决方案,只是一个半概念证明,以展示我们如何使用我们的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会注册,并覆盖现有的端点,无论是杰克逊还是我们的。

当然我们不想真正做到这一点,它只是展示了如何覆盖映射器。我无法弄清楚的是放置此代码的位置。我在ServletContextListener构造函数中尝试了Application Feature的优先级较低的app.directive('myDraggable', function($document) { return function($scope, $element, $attr) { document.body.addEventListener('click', function () { $scope.loggedInOpened = !$scope.loggedInOpened; $scope.$apply(); }, false); } }); 。我无法弄明白。在RESTeasy 最终注册之前,上述情况均未发生。