Wildfly:未使用 RestEasy JSR-303 Bean 验证触发 ExceptionMapper

Wildfly: ExceptionMapper not triggered with RestEasy JSR-303 Bean Validation

我在 Wildfly 8.2 中将 Bean 验证与 RestEasy 结合使用。0.Final:

@Path("/user")
@Produces(MediaType.APPLICATION_JSON)
public class UserEndpoint
{
    //more code

    @GET
    @Path("/encrypt/{email}")
    public Response fetchEncryptedId(@PathParam("email") @NotNull String email)
    {
        String encryptedUserId = userService.getEncryptedUserId(email);

        return Response.ok().entity(new UserBo(encryptedUserId)).build();
    }
}

这基本上有效。现在我想得到 JSON 对象的响应,但我无法让它工作。我所有的 "application" 异常都由我的异常映射器处理,这有效:

@Provider
public class DefaultExceptionMapper implements ExceptionMapper<Exception>
{
    private static final String MEDIA_TYPE = "application/json";

    private LoggingService loggingService;

    @EJB
    public void setLoggingService(LoggingService loggingService)
    {
        this.loggingService = loggingService;
    }

    @Override
    public Response toResponse(Exception exception)
    {
        ResponseObject responseObject = new ResponseObject();
        responseObject.registerExceptionMessage(exception.getMessage());

        if (exception instanceof ForbiddenException)
        {
            loggingService.log(LogLevel.ERROR, ((ForbiddenException)exception).getUserId(), ExceptionToStringMapper.map(exception));
            return Response.status(Status.FORBIDDEN).type(MEDIA_TYPE).entity(responseObject).build();
        }

        //more handling

        loggingService.log(LogLevel.ERROR, "", ExceptionToStringMapper.map(exception));
        return Response.status(Status.INTERNAL_SERVER_ERROR).type(MEDIA_TYPE).entity(responseObject).build();
    }
}

但是 bean 验证以某种方式绕过了它。然后我考虑使用 Throwable 而不是 Exception 但它也没有帮助。我猜 ExceptionMapper 没有被触发,因为 JAX-RS 和 JSR303 存在一些生命周期问题。但是我怎样才能同步它们来处理 bean 验证异常呢? 附加信息:异常通过 javax.ws.rs.container.ContainerResponseFilter 因此我可以通过在子类中实现 filter 方法来编写一些解决方法,但这不是干净的解决方案。目标是处理异常映射器中的异常。

您的 ExceptionMapper<Exception> 并不总是会捕获 Exception 层次结构下的所有异常。如果有另一个更具体的映射器,比如 RuntimeException 那个 映射器将用于 RuntimeException 及其子类型的所有异常。

也就是说(假设您使用的是 resteasy-validation-provider-11),已经有一个 ResteasyViolationExceptionMapper 可以处理 ValidationException

@Provider
public class ResteasyViolationExceptionMapper 
        implements ExceptionMapper<ValidationException>

此映射器已自动注册。它 returns 的结果是 ViolationReport 的形式。客户端需要将 Accept header 设置为 application/json 才能看到类似于

的响应
{
  "exception":null,
  "fieldViolations":[],
  "propertyViolations":[],
  "classViolations":[],
  "parameterViolations":[
    {
      "constraintType":"PARAMETER",
      "path":"get.arg0",
      "message":"size must be between 2 and 2147483647",
      "value":"1"}
  ],
  "returnValueViolations":[]
}

您可以在 Violation reporting 查看更多内容。

如果你想完全覆盖这个行为,你可以为ResteasyViolationException创建一个更具体的映射器,这是RESTeasy验证器抛出的异常

@Provider
public class MyValidationMapper
        implements ExceptionMapper<ResteasyViolationException> {

    @Override
    public Response toResponse(ResteasyViolationException e) {

    }
}