如何处理 jackson 与 Camel REST DSL 绑定的异常?

How to handle exceptions from jackson binding with Camel REST DSL?

我正在使用 Camel 2.14.1 构建一些 RESTful 服务,这些服务使用 Camel REST DSL 的 Jackson json 绑定功能。这工作得很好,但我希望能够在绑定过程中出现问题时向客户端发送自定义响应。

例如,如果在将输入字符串值转换为整数时抛出 NumberFormatException,因为客户端错误地发送了不是数字的字符。此异常不是 Jackson 特定的异常,因此我无法捕获它以使用绑定失败消息回复客户端,因为它可能是合法的内部错误。

同样,我想捕获在 json 到 POJO 的入站绑定期间抛出的任何其他异常,并以类似的方式处理这些异常,至少通知客户端他们的有效负载是无效。

因为这些都是我的代码处理的 "above",我看不出如何轻松处理此类错误,因为它们都是在我无法控制的库中处理的。 我正在使用 Camel 的 onException 子句来处理我自己的异常,所以我知道这一点,只是不确定如何准确地实现我需要的...

最坏的情况,我想我可以将每个客户端输入作为一个字符串并自己绑定它,但这似乎违背了杰克逊的观点。

tl;博士: Camel 中是否有一种模式允许我使用 REST DSL return 当 Jackson 的 POJO 绑定失败时自定义响应?

编辑 - 这里有一些伪代码来说明我正在尝试做的事情:

class errorHandler {

  void handleException(Exchange exchange, @ExchangeException Exception exception) {

    if (myException.class.isAssignableFrom(exception.getClass())) {
      // Set exchange body and response code header
      // This works as expected, though could probably do this more nicely
    }

    else if (camelBindingOrJacksonBindingException) {
      // Some other custom handling like above, but specific for these exception types
    }

    else {
      // Generic catch all with generic error response body
      // This also works fine
    }
  }
}

目前我最终在最后的 else 块中捕获了 binding/Jackson 异常,这正是我试图避免的,因为实际上让客户知道他们的输入无效会更有用。这似乎等同于下面 isaac.hazan 的回答。

这样做的问题是,我无法找到 Jackson 绑定异常是否有一个我可以捕获的父 class,所有此类可能异常的列表,或告诉它出现的方式来自绑定。

第二个问题是,当 Camel 期望来自 @Header int number 等方法的绑定注释的 int 时,我无法判断 NumberFormatException 这样的 camel 绑定异常是否真的来自 Camel,或者从我自己的代码。非常不愿意接受任何旧的 NumberFormatException,因为如果进一步的内部更改可能会抛出这个问题,我最终会 returning 一个不正确的响应。是否有某种方法可以找出异常的来源(是否在绑定时)?

我在我的一个应用程序中遇到了类似的问题。我通过一个专用处理器解决了这个问题,该处理器为每种类型的异常提供了一种方法。

例如,您可以有以下 2 个处理程序,一个作为特定异常,另一个用于任何其他异常:

    <onException id="handleAmazonServiceException">
        <exception>com.amazonaws.AmazonServiceException</exception>
        <handled><constant>true</constant></handled>
        <bean ref="errorHandlerProcessor" method="handleAmazonServiceException" />
        <setHeader headerName="CamelFileName">
            <simple>{{local.failed.records.dir}}/${header.S3Prefix}/${date:now:yyyy-MM-dd}/${header.failedRecordFileName}</simple>
        </setHeader>
        <to id="failedRecordsFile" uri="ref:s3FailedRecordsEndpoint" />
    </onException>

    <onException id="handleGeneralException">
        <exception>org.apache.camel.CamelExecutionException</exception>
        <exception>java.lang.Exception</exception>
        <handled><constant>true</constant></handled>
        <bean ref="errorHandlerProcessor" method="handleGeneralException" />
        <setHeader headerName="CamelFileName">
            <simple>{{local.failed.records.dir}}/${header.S3Prefix}/${date:now:yyyy-MM-dd}/${header.failedRecordFileName}</simple>
        </setHeader>
        <to id="failedRecordsFile" uri="ref:s3FailedRecordsEndpoint" />
    </onException>

上面的关键是"errorHandlerProcessor" bean,它负责处理任何类型的异常。这是一种从一个地方处理所有错误的简单方法。

看起来像这样:

@Service(value = "errorHandlerProcessor")
public class ErrorHandlerProcessor
{
// General handler
public void handleGeneralException(Exchange exchange)
{
    Throwable caused = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Throwable.class);
    logger.error("An unexpected error camel error occurred:" + caused.getMessage());
    logger.debug("Caught exception within the camel engine:", caused);
    ...
}

//AmazonClientException handler
public void handleAmazonClientException(Exchange exchange)
{
    AmazonClientException caused = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, AmazonClientException.class);
    StringBuffer errorMessage = new StringBuffer();
    errorMessage.append("AmazonClientException,AWS communication problem, Error Message: " + caused.getMessage());
    ...
}
}

最后,我对在 Jackson 的 javadoc 中能找到的任何内容都使用了 Camel onException 子句。这些是 JsonMappingExceptionJsonParseException(尽管您可以更进一步选择其他子类)。

为了处理 Camel 绑定问题,我最终使用 @Header 属性 作为字符串从 Camel Headers 绑定了东西,并进行了我自己的输入验证、解析等。这让我抛出我自己的自定义异常,因此在 onException 子句中处理它们。

不确定是否有更好的方法,如果有的话会很高兴!