java - 如何在 Jackson 编码(marshal)期间在 Apache Camel 路由中捕获 JsonParseException?

标签 java json exception jackson apache-camel

我通过 HTTP-POST 向我的 Camel-Spark-REST 组件发送一个无效 JSON 正文。在我的 Camel 路线上,JSON 主体将使用 Jackson 库从 JSON 转换(编码(marshal))为 Java 对象。由于 JSON 正文无效,编码(marshal)失败。使用camel doTry/doCatch 元素,我 try catch 异常并由我自己处理它们。看起来像这样:

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 编码(marshal)拆收器将抛出 JsonParseException。正如您在上面看到的,我 try catch JsonParseException 异常,它应该在我的控制台上输出发生 JsonParseException

但异常是未捕获,我在控制台上获得了完整的堆栈跟踪:

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]

根据我的测试,这种情况发生在 .marshal().json(JsonLibrary.Jackson) 部分。如果我发送有效的 JSON 主体并在第一个处理器中手动抛出 JsonParseException(请参阅注释行),则将捕获异常。 Exception.class catch block 也永远不会被调用,因此可以排除它,因为我 try catch “错误”的异常。是否有机会捕获 Jackson 编码(marshal)拆收器中的异常,或者是否有一个 Camel 组件来检查 JSON 主体(如果格式良好),我可以将其放在编码(marshal)拆收器前面?

最佳答案

异常可能会在端点中引发,而不是在编码步骤中引发。我不知道 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 绑定(bind)或请求/响应处理策略可能会更容易。同样,我不知道 Spark-rest 端点,但是使用 Jetty,您可以提供自己的 http 绑定(bind)实现,如下所示:

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>

关于java - 如何在 Jackson 编码(marshal)期间在 Apache Camel 路由中捕获 JsonParseException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41723635/

相关文章:

java - 从 Java 调用 Mongodb 的 load() 函数

javascript - 从 Google Apps Script 中的 api 解析 JSON 响应

asp.net-mvc - 在 asp.net-mvc 站点上优化 json 的最佳方法是什么

json - PostgreSQL,根据并行属性的值获取JSON对象字段

c++ - 如何在发生异常时运行代码

java - Google Spreadsheet getFeed 错误和理解

java - SimGrid。模拟异常情况

java - 空对象引用上的 OnItemClick.onItemClick(int) 异常?

mysql - 我如何处理 CAMEL jdbc 连接异常?

java - JDK RSACore.priCrypt 如何工作以及 getBlindingRandomPair 是什么意思?