Apache Camel - 从Rest读取Json,然后转换为Java Object

时间:2016-09-29 08:06:09

标签: java json rest apache-camel

目前,我的申请可以

  1. 从本地文件系统
  2. 读取json文件
  3. 使用Jackson Library的ObjectMapper转换为Java对象
  4. 现在,我想将流程更改为

    1. 从rest endpoint
    2. 读取json内容
    3. 记录json内容
    4. 使用Jackson Library的ObjectMapper转换为Java对象
    5. 但是,我遇到一个奇怪的问题,即身体在交换后会在显示后消失。想知道我错过了什么可能的设置?

      XML内容

      <camelContext id="admin_sysHttpRec_ctx" xmlns="http://camel.apache.org/schema/spring" trace="false">
      
          <restConfiguration component="restlet" host="localhost" port="9394"></restConfiguration>
      
          <rest path="/sys">
              <put uri="/json" id="admin_sysHttpJson_receiver">
                  <to uri="direct:sysJson.process"/>
              </put>
          </rest>
      
          <route id="admin_sysHttpJson_route">
              <from uri="direct:sysJson.process"/>
              <log message="sysHttpJsonManage BODY: ${body}" loggingLevel="INFO" />
              <process ref="sysJsonManage"/>
              <transform>
                  <constant>Success!</constant>
              </transform>
          </route>
      
      </camelContext>
      

      处理器

      @Override
      public void process(Exchange exchange) throws Exception {
          LOG.info("body: " + exchange.getIn().getBody(String.class));
      
          // Setup jsonFileContext
          //      byte[] body = exchange.getIn().getBody(byte[].class);
          String bodyStr = exchange.getIn().getBody(String.class);
          byte[] body = bodyStr.getBytes();
          LOG.info("body.length: " + body.length);
          LOG.info("(String) body.length: " + exchange.getIn().getBody(String.class).length());
      
          try {
              ObjectMapper objectMapper = new ObjectMapper();
              JsonFileContext jsonFileContext = objectMapper.readValue(body, JsonFileContext.class);
              exchange.setProperty("jsonFileContext", jsonFileContext);
          } catch (Exception e) {
              exchange.setException(e);
          }
      }
      

      http请求中的原始有效负载

      {
          "direction":"OUT",
          "srcEncoding":"",
          "destEncoding":""
      }
      

      结果

      20160929 15:53:33.193 [Restlet-4844614] INFO admin_sysHttpJson_route - sysHttpJsonManage BODY: {
          "direction":"OUT",
          "srcEncoding":"",
          "destEncoding":""
      }
      20160929 15:53:33.193 [Restlet-4844614] INFO com.test.admin.sys.http.SysJsonManage - body: 
      20160929 15:53:33.194 [Restlet-4844614] INFO com.test.admin.sys.http.SysJsonManage - body.length: 0
      20160929 15:53:33.194 [Restlet-4844614] INFO com.test.admin.sys.http.SysJsonManage - (String) body.length: 0
      20160929 15:53:33.355 [Restlet-4844614] ERROR org.apache.camel.processor.DefaultErrorHandler - Failed delivery for (MessageId: ID-XXXXX-61466-1475135595982-0-1 on ExchangeId: ID-XXXXX-61466-1475135595982-0-2). Exhausted after delivery attempt: 1 caught: com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input
       at [Source: [B@67e6a2; line: 1, column: 1]
      
      Message History
      ---------------------------------------------------------------------------------------------------------------------------------------
      RouteId              ProcessorId          Processor                                                                        Elapsed (ms)
      [admin_sysHttpJson_] [admin_sysHttpJson_] [http://localhost:9394/sys/json?restletMethods=PUT                             ] [       181]
      [admin_sysHttpJson_] [restBinding1      ] [                                                                              ] [         4]
      [admin_sysHttpJson_] [admin_sysHttpJson_] [direct:sysJson.process                                                        ] [       162]
      [admin_sysHttpJson_] [log1              ] [log                                                                           ] [         0]
      [admin_sysHttpJson_] [process1          ] [ref:sysJsonManage                                                             ] [       160]
      
      Stacktrace
      ---------------------------------------------------------------------------------------------------------------------------------------
      com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input
       at [Source: [B@67e6a2; line: 1, column: 1]
          at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
          at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:3781)
          at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3721)
          at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2819)
          at com.test.admin.sys.http.SysJsonManage.process(SysJsonManage.java:31)
          at org.apache.camel.processor.DelegateSyncProcessor.process(DelegateSyncProcessor.java:63)
          at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:77)
          at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:468)
          at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:190)
          at org.apache.camel.processor.Pipeline.process(Pipeline.java:121)
          at org.apache.camel.processor.Pipeline.process(Pipeline.java:83)
          at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:190)
          at org.apache.camel.component.direct.DirectProducer.process(DirectProducer.java:62)
          at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:145)
          at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:77)
          at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:468)
          at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:190)
          at org.apache.camel.processor.Pipeline.process(Pipeline.java:121)
          at org.apache.camel.processor.Pipeline.process(Pipeline.java:83)
          at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:190)
          at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:109)
          at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:87)
          at org.apache.camel.component.restlet.RestletConsumer$1.handle(RestletConsumer.java:68)
          at org.apache.camel.component.restlet.MethodBasedRouter.handle(MethodBasedRouter.java:54)
          at org.restlet.routing.Filter.doHandle(Filter.java:150)
          at org.restlet.routing.Filter.handle(Filter.java:197)
          at org.restlet.routing.Router.doHandle(Router.java:422)
          at org.restlet.routing.Router.handle(Router.java:639)
          at org.restlet.routing.Filter.doHandle(Filter.java:150)
          at org.restlet.routing.Filter.handle(Filter.java:197)
          at org.restlet.routing.Router.doHandle(Router.java:422)
          at org.restlet.routing.Router.handle(Router.java:639)
          at org.restlet.routing.Filter.doHandle(Filter.java:150)
          at org.restlet.engine.application.StatusFilter.doHandle(StatusFilter.java:140)
          at org.restlet.routing.Filter.handle(Filter.java:197)
          at org.restlet.routing.Filter.doHandle(Filter.java:150)
          at org.restlet.routing.Filter.handle(Filter.java:197)
          at org.restlet.engine.CompositeHelper.handle(CompositeHelper.java:202)
          at org.restlet.Component.handle(Component.java:408)
          at org.restlet.Server.handle(Server.java:507)
          at org.restlet.engine.connector.ServerHelper.handle(ServerHelper.java:63)
          at org.restlet.engine.adapter.HttpServerHelper.handle(HttpServerHelper.java:143)
          at org.restlet.engine.connector.HttpServerHelper$1.handle(HttpServerHelper.java:64)
          at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79)
          at sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:83)
          at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:82)
          at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:675)
          at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79)
          at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:647)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
          at java.lang.Thread.run(Thread.java:745)
      

      我使用的Camel版本是2.17.0

2 个答案:

答案 0 :(得分:3)

错误消息说明了一切:输入消息正文是一个流(例如InputStream),只能被消费一次。一种解决方案是全局(对于Camel上下文中的所有路由)或每个路由启用流缓存。有关详细信息,请参阅the official documentation

XML - 全局配置:

<camelContext streamCache="true">
    ...
</camelContext>

XML - 单一路线:

<route streamCache="true">
    ...
</route>

Java - 全局配置:

context.setStreamCache(true);

Java - 单一路线:

from("...")
.streamCaching()
.to("...");

值得注意的是,您可以使用Camel的JSON DataFormat和DSL中的unmarshall步骤,而不是使用处理器手动反序列化您的JSON输入。

甚至更简单,只需配置REST端点为您执行绑定并输出POJO,方法是配置REST DSL中的bindingMode。像这样的东西应该做的伎俩(我只测试了Java DSL,希望XML语法是正确的):

<restConfiguration component="restlet" host="localhost" port="9394" bindingMode="json" />

<rest path="/sys">
    <put uri="/json" id="admin_sysHttpJson_receiver" type="JsonFileContext.class">
        <to uri="direct:sysJson.process"/>
    </put>
</rest>

在这两种情况下,您都需要类路径上的camel-jackson组件。

答案 1 :(得分:0)

感谢@kostyan_SV和@Cyäegha指出InputStream中的问题来源。

由于问题源自InputStream,我能想到的一个简单解决方案是通过convertBodyTo功能将体型从InputStream转换为String。

<route id="admin_sysHttpJson_route">
    <from uri="direct:sysJson.process"/>
    <convertBodyTo type="java.lang.String"/>
    ...
</route>

注意如果不需要在休息端点和解组步骤之间进行与原始有效负载相关的任何工作,最好使用@Cyäegha建议的bindingMode方法。