Java 如何在Jackson封送期间捕获ApacheCamel路由中的JsonParseException?
我通过HTTP-POST向我的Camel Spark REST组件发送一个无效的JSON正文。在我的驼峰路线上,JSON主体将通过Jackson库从JSON转换(封送)为Java对象。封送处理失败,因为JSON正文无效。使用camel doTry/doCatch元素,我尝试捕获异常并自己处理它们。这看起来像这样:Java 如何在Jackson封送期间捕获ApacheCamel路由中的JsonParseException?,java,json,exception,jackson,apache-camel,Java,Json,Exception,Jackson,Apache Camel,我通过HTTP-POST向我的Camel Spark REST组件发送一个无效的JSON正文。在我的驼峰路线上,JSON主体将通过Jackson库从JSON转换(封送)为Java对象。封送处理失败,因为JSON正文无效。使用camel doTry/doCatch元素,我尝试捕获异常并自己处理它们。这看起来像这样: rest("/v1/users") .consumes("application/json") .produces("application/json") .post(
rest("/v1/users")
.consumes("application/json")
.produces("application/json")
.post("/insert")
.to("direct:restInput");
from("direct:restInput")
.doTry()
.marshal().json(JsonLibrary.Jackson)
[...]
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
//throw new JsonParseException(null, "");
}
})
[...]
.doCatch(JsonParseException.class)
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
System.out.println("JsonParseException occured");
}
})
.doCatch(Exception.class)
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
System.out.println("Exception occured");
}
})
.end()
.marshal();
如果存在无效的JSON正文,则Jackson封送处理程序将抛出JsonParseException。正如您在上面所看到的,我尝试捕获JsonParseException异常,它应该在我的控制台上输出JsonParseException Occursed
但是例外情况是未被捕获,我在控制台上获得完整的堆栈跟踪:
Message History
---------------------------------------------------------------------------------------------------------------------------------------
RouteId ProcessorId Processor Elapsed (ms)
[route4 ] [route4 ] [spark-rest://post:v1/users/insert?accept=application%2Fjson ] [ 42]
[route4 ] [restBinding4 ] [ ] [ 39]
Stacktrace
---------------------------------------------------------------------------------------------------------------------------------------
com.fasterxml.jackson.core.JsonParseException: Unexpected character (':' (code 58)): was expecting comma to separate Array entries
at [Source: java.io.ByteArrayInputStream@1aa6eb2; line: 23, column: 17]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1702) ~[jackson-core-2.8.3.jar:2.8.3]
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:558) ~[jackson-core-2.8.3.jar:2.8.3]
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:456) ~[jackson-core-2.8.3.jar:2.8.3]
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.nextToken(UTF8StreamJsonParser.java:761) ~[jackson-core-2.8.3.jar:2.8.3]
at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.mapArray(UntypedObjectDeserializer.java:594) ~[jackson-databind-2.8.3.jar:2.8.3]
at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.deserialize(UntypedObjectDeserializer.java:510) ~[jackson-databind-2.8.3.jar:2.8.3]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3789) ~[jackson-databind-2.8.3.jar:2.8.3]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2899) ~[jackson-databind-2.8.3.jar:2.8.3]
at org.apache.camel.component.jackson.JacksonDataFormat.unmarshal(JacksonDataFormat.java:172) ~[camel-jackson-2.18.0.jar:2.18.0]
at org.apache.camel.processor.UnmarshalProcessor.process(UnmarshalProcessor.java:69) ~[camel-core-2.18.0.jar:2.18.0]
at org.apache.camel.component.rest.RestConsumerBindingProcessor.process(RestConsumerBindingProcessor.java:189) ~[camel-core-2.18.0.jar:2.18.0]
at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:77) ~[camel-core-2.18.0.jar:2.18.0]
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:542) [camel-core-2.18.0.jar:2.18.0]
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:197) [camel-core-2.18.0.jar:2.18.0]
at org.apache.camel.processor.Pipeline.process(Pipeline.java:120) [camel-core-2.18.0.jar:2.18.0]
at org.apache.camel.processor.Pipeline.process(Pipeline.java:83) [camel-core-2.18.0.jar:2.18.0]
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:197) [camel-core-2.18.0.jar:2.18.0]
at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:97) [camel-core-2.18.0.jar:2.18.0]
at org.apache.camel.component.sparkrest.CamelSparkRoute.handle(CamelSparkRoute.java:46) [camel-spark-rest-2.18.0.jar:2.18.0]
at spark.RouteImpl$1.handle(RouteImpl.java:58) [spark-core-2.3.jar:?]
at spark.webserver.MatcherFilter.doFilter(MatcherFilter.java:162) [spark-core-2.3.jar:?]
at spark.webserver.JettyHandler.doHandle(JettyHandler.java:61) [spark-core-2.3.jar:?]
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:189) [jetty-server-9.2.19.v20160908.jar:9.2.19.v20160908]
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) [jetty-server-9.2.19.v20160908.jar:9.2.19.v20160908]
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97) [jetty-server-9.2.19.v20160908.jar:9.2.19.v20160908]
at org.eclipse.jetty.server.Server.handle(Server.java:499) [jetty-server-9.2.19.v20160908.jar:9.2.19.v20160908]
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311) [jetty-server-9.2.19.v20160908.jar:9.2.19.v20160908]
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257) [jetty-server-9.2.19.v20160908.jar:9.2.19.v20160908]
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544) [jetty-io-9.2.19.v20160908.jar:9.2.19.v20160908]
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635) [jetty-util-9.2.19.v20160908.jar:9.2.19.v20160908]
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555) [jetty-util-9.2.19.v20160908.jar:9.2.19.v20160908]
at java.lang.Thread.run(Thread.java:745) [?:1.8.0_101]
根据我的测试,这种情况发生在
.marshall().json(JsonLibrary.Jackson)
部分。如果我发送一个有效的JSON正文,并在第一个处理器中手动抛出JsonParseException(请参见注释行),那么将捕获异常。Exception.class
catch块也永远不会被调用,因此它可能被排除,我试图捕获“错误”的异常。是否有机会捕获Jackson封送处理程序中的异常,或者是否有检查JSON正文(如果格式正确)的Camel组件,我可以将其放在封送处理程序前面?异常可能会在端点中抛出,而不是在封送处理步骤中抛出。我不知道spart rest端点,但是对于Jetty端点和rest DSL,编组错误会在Jetty端点本身中抛出。除了堆栈跟踪之外,Camel还应该记录消息历史记录。您可以在历史记录中验证是否执行了编组步骤
2017-01-19 09:11:28,040 | ERROR | qtp762554626-172 | DefaultErrorHandler | 75 - org.apache.camel.camel-core - 2.16.3 | | Failed delivery for (MessageId: ID-Ralfs-MacBook-Pro-local-60691-1484813099793-0-2 on ExchangeId: ID-Ralfs-MacBook-Pro-local-60691-1484813099793-0-1). Exhausted after delivery attempt: 1 caught: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('n' (code 110)): was expecting double-quote to start field name
at [Source: java.io.ByteArrayInputStream@49828827; line: 33, column: 6]
Message History
---------------------------------------------------------------------------------------------------------------------------------------
RouteId ProcessorId Processor Elapsed (ms)
[route1 ] [route1 ] [jetty:http://0.0.0.0:8282/some/path?httpMethodRestrict=PUT ] [ 15]
[route1 ] [restBinding1 ] [ ] [ 12]
Exchange
---------------------------------------------------------------------------------------------------------------------------------------
Exchange[
Id ID-Ralfs-MacBook-Pro-local-60691-1484813099793-0-1
ExchangePattern InOut
[..]
Stacktrace
---------------------------------------------------------------------------------------------------------------------------------------
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('n' (code 110)): was expecting double-quote to start field name
at [Source: java.io.ByteArrayInputStream@49828827; line: 33, column: 6]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1581)[55:com.fasterxml.jackson.core.jackson-core:2.6.3]
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:533)[55:com.fasterxml.jackson.core.jackson-core:2.6.3]
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:462)[55:com.fasterxml.jackson.core.jackson-core:2.6.3]
[..]
如果在端点上确实抛出了异常,那么自定义错误处理的选项取决于您希望执行的错误处理类型
正如您自己所建议的,您可以使用全局onException
处理程序来使用处理器来处理错误。
如果您只想控制客户端接收的错误消息和http响应代码的类型,那么提供自己的http绑定或请求/响应处理策略可能会更容易。我也不知道spark rest端点,但使用Jetty,您可以提供自己的http绑定实现,如下所示:
public class JettyNoStacktraceHttpBinding extends JettyRestHttpBinding {
private static final int BAD_REQUEST = 400;
@Override
public void doWriteExceptionResponse(Throwable exception, javax.servlet.http.HttpServletResponse response) throws java.io.IOException {
if (exception instanceof JsonParseException) {
response.setStatus(BAD_REQUEST);
response.setContentType("text/plain");
PrintWriter pw = response.getWriter();
pw.print(exception.getMessage());
pw.flush();
}
}
}
<restConfiguration contextPath="/some/path" component="jetty" scheme="http" host="0.0.0.0" port="8282" bindingMode="json">
<endpointProperty key="httpBindingRef" value="jettyNoStackTraceHTTPBinding" />
<!-- ... -->
</restConfiguration>
公共类JettyNoStacktraceHttpBinding扩展了JettyRestHttpBinding{
私有静态最终int BAD_请求=400;
@凌驾
public void doWriteExceptionResponse(Throwable exception,javax.servlet.http.HttpServletResponse)抛出java.io.IOException{
if(JsonParseException的异常实例){
响应。设置状态(错误的请求);
response.setContentType(“文本/普通”);
PrintWriter pw=response.getWriter();
print(exception.getMessage());
pw.flush();
}
}
}
您确定在.marshall().json(JsonLibrary.Jackson)
行上引发了异常吗?我不知道spark rest端点,但是当将jetty端点与rest DSL一起使用时,com.fasterxml.jackson.core.JsonParseException
在端点本身中引发。不在后续编组步骤中。在stacktrace旁边,您还应该看到日志中的消息历史记录。你能不能也发布这个消息和/或检查历史记录是否包含编组步骤?你说得对@Ralf,我检查了历史记录,它发生在restBinding中。对不起,我完全忽略了那部分。但是不可能将“doTry/doCatch”部分放在.post(“…”)部分之前。所以,我不能使用doTry/doCatch,或者你是如何解决这个问题的?您使用了OneException吗?谢谢@Ralf,还有OneException(JsonParseException.class).handled(true.to)(“…”);在全球范围内,它起作用。如果你想以anwser的身份发表你的评论,我会接受它作为“最佳答案”。谢谢你的回答。OneException部分工作正常。我还尝试了您的请求/响应处理程序。我搜索了一个抽象类而不是Jetty,结果发现,org.apache.camel.component.http4 DefaultHttpBinding或HttpBinding中应该有。但在Camel 2.17.3/2.18.0中,它丢失了。我在2.15.0中找到了它。他们是否删除了它并忘记更新文档?如果是的话,现在有什么选择?如果你不知道,我可以问另一个问题。@Zeussi,最好问一个新问题。