如何处理 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
子句。这些是 JsonMappingException
和 JsonParseException
(尽管您可以更进一步选择其他子类)。
为了处理 Camel 绑定问题,我最终使用 @Header
属性 作为字符串从 Camel Headers 绑定了东西,并进行了我自己的输入验证、解析等。这让我抛出我自己的自定义异常,因此在 onException
子句中处理它们。
不确定是否有更好的方法,如果有的话会很高兴!
我正在使用 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
子句。这些是 JsonMappingException
和 JsonParseException
(尽管您可以更进一步选择其他子类)。
为了处理 Camel 绑定问题,我最终使用 @Header
属性 作为字符串从 Camel Headers 绑定了东西,并进行了我自己的输入验证、解析等。这让我抛出我自己的自定义异常,因此在 onException
子句中处理它们。
不确定是否有更好的方法,如果有的话会很高兴!