You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Quarkus中通用ExceptionMapper<Throwable>无法处理部分异常的咨询

问题:通用ExceptionMapper为何无法处理ResteasyReactiveViolationException,却能处理RuntimeException?

已实现的通用ExceptionMapper

@Provider
@JBossLog
public class RestExceptionMapper implements ExceptionMapper<Throwable> {

   @Context
   HttpServerRequest request;

   @Context
   SecurityContext securityContext;

   @Context
   UriInfo uriInfo;

   @Override
   public Response toResponse(Throwable exception) {
      final Throwable rootCause = ExceptionUtils.getRootCause(exception);
      log.errorf("General exception: %s", rootCause.getMessage(), rootCause);
      return Response.status(Status.INTERNAL_SERVER_ERROR).build();
   }
}

已实现的REST资源类

@Path("/process-settings")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ProcessSettingResource {

    @POST
    @RunOnVirtualThread
    public RestResponse<Object> createProcessSetting(
        @Valid CreateProcessSettingDto processSettingDto,
        @Context UriInfo uriInfo
    ) {
        URI location = uriInfo.getAbsolutePathBuilder()
            .path(String.valueOf(1L))
            .build();

        if (processSettingDto.getProcessInfo().getProcessName().equals("FAIL")) {
            // ResteasyReactiveViolationException 不会被 RestExceptionMapper 处理
            throw new ResteasyReactiveViolationException("Process Name is invalid", new HashSet<>());

            // RuntimeException 会被 RestExceptionMapper 处理
            // throw new RuntimeException("Process Name is invalid");

            // IllegalArgumentException 会被 RestExceptionMapper 处理
            // throw new IllegalArgumentException("Process Name is invalid");
        }

        return ResponseBuilder.create(Status.CREATED).location(location).build();
    }
}

疑问

为何ResteasyReactiveViolationException或其父类ConstraintViolationException无法被该通用ExceptionMapper处理,而RuntimeException、IllegalArgumentException却可以?这是Bug还是特性?规则出处在哪里?


更新内容

Quarkus的JAX-RS组件开发者已指向相关Issue及PR,但暂未了解方案细节。调试时发现Quarkus Resteasy预定义了针对以下异常的ExceptionMapper:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException
io.quarkus.security.AuthenticationRedirectException
com.fasterxml.jackson.databind.exc.MismatchedInputException
io.quarkus.security.UnauthorizedException
jakarta.validation.ValidationException
io.quarkus.security.ForbiddenException
io.quarkus.security.AuthenticationFailedException
io.quarkus.security.AuthenticationCompletionException

根据规范,上述异常或其子类会被预定义Mapper优先处理。目前已通过包装异常解决问题,也可实现特定异常的Mapper,希望Quarkus/Resteasy社区给出官方处理方案。


解答

这是Quarkus Resteasy的特性,而非Bug,核心原因源于JAX-RS规范的ExceptionMapper优先级规则,以及Quarkus的内置实现:

  1. JAX-RS规范的优先级逻辑
    JAX-RS容器在选择ExceptionMapper时,会优先匹配最具体的类型。也就是说,针对某个异常的直接父类的Mapper,优先级高于通用的Throwable Mapper。比如,针对ValidationException的Mapper会比你的ExceptionMapper<Throwable>优先级更高。

  2. 内置Mapper的拦截作用
    ResteasyReactiveViolationException的继承链是:ResteasyReactiveViolationException → ConstraintViolationException → ValidationException。而Quarkus内置了针对jakarta.validation.ValidationException的ExceptionMapper,所以当抛出ResteasyReactiveViolationException时,这个内置的、更具体的Mapper会被选中处理,你的通用Mapper就不会被触发。

  3. RuntimeException/IllegalArgumentException可被处理的原因
    这两个异常没有对应的Quarkus内置Mapper(没有比Throwable更具体的内置Mapper匹配它们),所以你的通用ExceptionMapper<Throwable>会被选中处理这些异常。

可行处理方案

  • 自定义特定异常Mapper:
    实现针对ResteasyReactiveViolationException或ConstraintViolationException的Mapper,由于它比内置的ValidationException Mapper更具体,会被优先调用:
    @Provider
    public class ResteasyReactiveViolationMapper implements ExceptionMapper<ResteasyReactiveViolationException> {
        @Override
        public Response toResponse(ResteasyReactiveViolationException exception) {
            // 自定义响应逻辑,比如返回400和错误信息
            return Response.status(Status.BAD_REQUEST)
                           .entity(Collections.singletonMap("error", exception.getMessage()))
                           .build();
        }
    }
    
  • 包装异常:
    像你目前的做法一样,将ResteasyReactiveViolationException包装到自定义RuntimeException中,绕过内置Mapper的拦截。
  • 禁用内置Validation Mapper:
    通过Quarkus配置项quarkus.resteasy-reactive.validation.disable-validation-exception-mapper=true关闭内置的Validation异常处理Mapper,这样你的通用Mapper就能处理这类异常。

内容的提问来源于stack exchange,提问作者joe_specimen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 08:52:35