使用 WebServices 时如何捕获原始异常?

How to catch the original Exception, when using WebServices?

现在搜索了几天并阅读了几乎所有与此相关的内容之后,我终于在这里发布了我的问题,因为我找不到针对我的特定问题的解决方案。

我希望我的 REST WebServices return 已抛出的原始异常或至少是正确的 StackTrace。为了对此进行测试,我使用 JUnit 集成测试和 Wildfly 13 作为应用服务器。经过研究,我发现了 2 种可能的解决方案。

1.Using 异常映射器

虽然这个神奇的东西捕获了我的所有异常并允许我 return 响应,但我注意到如果我像示例中那样使用它,我的 StackTrace 会发生变化。例如,"com.test.TestClass" 变为 "null.thread" 或 "null.interceptor"。似乎异常在途中以某种方式发生了变化,并且 class 的路径丢失或被审查了,但我无法理解它。 我也找不到 Response.entity 的任何限制,无论是大小、数据类型还是安全性。

据我了解,您可以捕获包含响应的 ExceptionMapper 响应或 WebApplicationException。就我而言,WebApplicationException 中的响应包含除(正确的)StackTrace 之外的所有相关数据。

2.Using WebApplicationException

另一种解决方案是简单地抛出 WebApplicationException 而不是 ECEException 并且不使用映射器。如果我这样做并抓住它,那么异常是空的。它不包含任何数据集,它始终为 500 - InternalServerError(我猜,Wildfly 无法处理它并自己抛出异常)。

或者它不应该是那样的 catched/thrown?我是否需要将它转换为 JSon 或者我是否可以期望它可以直接使用我在 WebServiceInterface 和 Response MediaType 中的注释工作?将完整的 Response 放入 WebApplicationException 中是否有意义?我的意思是,两者都包含 ErrorCode 的字段,这似乎是多余的,即使该方法有一个构造函数。

长话短说: 捕获所有可能的异常并检索完整堆栈跟踪的最佳方法是什么? Reading this post,我想捕捉所有 "Exception" 没问题,它们总是 returned 作为 WebApplicationExceptions,但堆栈跟踪仍然是 gone/malformed...你的想法?

    **JUnitTest** 
    @Test
    public void testCreateTask_ClusterInvalid() throws IOException {

        final RPETask taskToCreate = new RPETask();;

        try 
        {
            final long tid = taskManagerWebService.createTask(taskToCreate);
        } 
        catch (WebApplicationException e) //Responses are ALWAYS catched as WebApplicationException
        {

            Response response = e.getResponse();  
            String emString = response.readEntity(String.class);

            Gson gson = new Gson(); 

            ECEWebErrorMessage errorMessage = gson.fromJson(emString, ECEWebErrorMessage.class);       
            errorMessage.displayErrorInformationOnConsole();
        }
    }




    **WebServiceInterface**
    @POST
    @Path(URI_CREATE_TASK)
    @Consumes(WebServiceNames.JSON)
    @Produces(WebServiceNames.JSON)
    long createTask(final RPETask task) throws ECEException;




    **WebService**
    @Override
    public long createTask(final RPETask task) throws ECEException {
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("createTask(" + task + ")");
        }
        return taskManager.createTask(task);
    }




    **ManagerBeanInterface**
    long createTask(RPETask task) throws ECEException;




    **ManagerBean**
    @Override
    public long createTask(final RPETask task) throws ECEException {
        final ClusterEngineBean cluster = find(ClusterEngineBean.class, task.getCluster());
        if (cluster == null) {
            throw new ECEObjectNotFoundException(ClusterEngineBean.class, task.getCluster());
        }
    }




    **ExceptionMapper**
    @Provider
    public class GenericWebExceptionMapper implements ExceptionMapper<Exception> {
    final Log logger = LogFactory.getLog(getClass());

    @Override
    public Response toResponse(Exception ex) {

        //At this point, the Exception is fully available -> Sending it as Response breaks it!
        logger.error("GenericWebExceptionMapper -> toResponse(Throwable ex)", ex);

        ECEWebErrorMessage errorMessage = new ECEWebErrorMessage(500, 
                                                                 ex.getMessage(), 
                                                                 ex.getClass().getCanonicalName(),
                                                                 ex.getStackTrace());
        return Response.status(Status.INTERNAL_SERVER_ERROR)
                .entity(errorMessage)
                .type(MediaType.APPLICATION_JSON)
                .build();
        }
    }

经过更多研究,我终于找到了适合自己的解决方案。

为什么 StackTrace gone/malformed?

这是出于安全考虑。 Wildfly 使用拦截器自动检测传出的 StackTraces 并对其进行审查。我不确定你是否可以对此做任何事情,但我想你无论如何都不应该那样做。

最好的方法是什么?

使用异常映射器对我有用。与其将它们作为 WebApplicationException 捕获,您始终可以期望使用适当的错误代码进行响应并以这种方式处理它们。例如,错误代码 200 = OK,执行此操作...错误代码 404 = NOTFOUND,执行此操作...在这种情况下,您的 WebServices 应始终 return 响应并包含您要在实体字段中检索的对象响应。

随时向此解决方案添加其他信息。