У меня есть серверное и клиентское приложение, которое использует Apache Camel для настройки и управления их маршрутизацией. У меня есть случай использования, когда клиент делает запрос GET к серверу, и сервер должен отправлять обратно данные сообщения. Данные сообщения определяются классом generi c, который может содержать любой экземпляр объекта. В настоящее время я генерирую массив символов или байтов произвольной длины для полезной нагрузки сообщения.
У меня проблема с получением ответа GET на клиенте. Ниже приведены примеры клиентской и серверной консолей.
Клиентская консоль:
2020-04-10 14:42:38.678 INFO 19968 --- [ main] o.a.c.i.e.AbstractCamelContext : Route: rest-get started and consuming from: timer://http-get
2020-04-10 14:42:38.680 INFO 19968 --- [ main] o.a.c.i.e.AbstractCamelContext : Route: rest-post started and consuming from: timer://http-post
2020-04-10 14:42:38.684 INFO 19968 --- [ main] o.a.c.i.e.AbstractCamelContext : Total 2 routes, of which 2 are started
2020-04-10 14:42:38.684 INFO 19968 --- [ main] o.a.c.i.e.AbstractCamelContext : Apache Camel 3.1.0 (CamelContext: RESTClient) started in 1.715 seconds
...
2020-04-10 14:42:38.695 INFO 19968 --- [imer://http-get] rest-get : start - rest-get
2020-04-10 14:42:38.701 INFO 19968 --- [ main] e.m.l.m.ApplicationMain : Started ApplicationMain in 5.176 seconds (JVM running for 7.624)
2020-04-10 14:42:39.021 ERROR 19968 --- [imer://http-get] o.a.c.p.e.DefaultErrorHandler : Failed delivery for (MessageId: ID-489789-MITLL-1586544159020-0-1 on ExchangeId: ID-489789-MITLL-1586544159020-0-1). Exhausted after delivery attempt: 1 caught: java.lang.ClassCastException: org.apache.camel.converter.stream.CachedOutputStream$WrappedInputStream cannot be cast to edu.mit.ll.mission_services.model.GenericMessage
Message History (complete message history is disabled)
---------------------------------------------------------------------------------------------------------------------------------------
RouteId ProcessorId Processor Elapsed (ms)
[rest-get ] [rest-get ] [from[timer://http-get?delay=0&fixedRate=true&period=1000&repeatCount=1] ] [ 337]
...
[rest-get ] [process1 ] [ref:process-get-response ] [ 0]
Stacktrace
---------------------------------------------------------------------------------------------------------------------------------------
java.lang.ClassCastException: org.apache.camel.converter.stream.CachedOutputStream$WrappedInputStream cannot be cast to edu.mit.ll.mission_services.model.GenericMessage
at edu.mit.ll.mission_services.processor.GetResponseProcessor.process(GetResponseProcessor.java:18) ~[classes/:?]
at org.apache.camel.support.processor.DelegateSyncProcessor.process(DelegateSyncProcessor.java:64) ~[camel-support-3.1.0.jar:3.1.0]
at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:396) [camel-base-3.1.0.jar:3.1.0]
at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:153) [camel-base-3.1.0.jar:3.1.0]
at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:60) [camel-base-3.1.0.jar:3.1.0]
at org.apache.camel.processor.Pipeline.process(Pipeline.java:147) [camel-base-3.1.0.jar:3.1.0]
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:286) [camel-base-3.1.0.jar:3.1.0]
at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:198) [camel-timer-3.1.0.jar:3.1.0]
at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:78) [camel-timer-3.1.0.jar:3.1.0]
at java.util.TimerThread.mainLoop(Timer.java:555) [?:1.8.0_241]
at java.util.TimerThread.run(Timer.java:505) [?:1.8.0_241]
...
2020-04-10 14:42:41.182 INFO 19968 --- [mer://http-post] rest-post : start - rest-post
2020-04-10 14:42:41.455 INFO 19968 --- [mer://http-post] e.m.l.m.s.DataProvider : produceCharArrayData: generated 15775578 characters
2020-04-10 14:42:41.455 INFO 19968 --- [mer://http-post] e.m.l.m.p.AddPostRequestBody : adding POST request body:
GenericMessage [payload=[C@572d6e9b]
2020-04-10 14:42:43.497 INFO 19968 --- [mer://http-post] rest-post : end - rest-post
Серверная консоль:
2020-04-10 14:42:25.598 INFO 22860 --- [ main] o.a.c.i.e.AbstractCamelContext : Route: get-data-by-size started and consuming from: jetty:http://localhost:9100/data
2020-04-10 14:42:25.599 INFO 22860 --- [ main] o.a.c.i.e.AbstractCamelContext : Route: post-data started and consuming from: jetty:http://localhost:9100/post-data
2020-04-10 14:42:25.607 INFO 22860 --- [ main] o.a.c.i.e.AbstractCamelContext : Total 2 routes, of which 2 are started
2020-04-10 14:42:25.607 INFO 22860 --- [ main] o.a.c.i.e.AbstractCamelContext : Apache Camel 3.1.0 (CamelContext: RESTServer) started in 0.342 seconds
...
2020-04-10 14:42:38.901 INFO 22860 --- [qtp913796146-39] get-data-by-size : start - get-data-by-size
2020-04-10 14:42:38.902 INFO 22860 --- [qtp913796146-39] e.m.l.m.s.DataProvider : getCharData: size=500
2020-04-10 14:42:38.905 INFO 22860 --- [qtp913796146-39] get-data-by-size : end - get-data-by-size
2020-04-10 14:42:43.097 INFO 22860 --- [qtp913796146-34] post-data : start - post-data
2020-04-10 14:42:43.100 WARN 22860 --- [qtp913796146-34] e.m.l.m.p.PostRequestProcessor : process: null object
2020-04-10 14:42:43.100 INFO 22860 --- [qtp913796146-34] post-data : end - post-data
После некоторого дальнейшего чтения и экспериментов, я думаю, я нашел решение.
Первое, что я попробовал, это добавление блока <unmarshal>
перед моим процессором следующим образом:
<route id="rest-get">
<from
uri="timer:{{http-client.timers.http-get.name}}?delay={{http-client.timers.http-get.start-delay}}&fixedRate=true&period={{http-client.timers.http-get.period}}&repeatCount={{http-client.timers.http-get.repeat-count}}" />
<log loggingLevel="INFO" message="start - rest-get" />
<to uri="rest:get:{{http-client.endpoints.http-get}}" />
<unmarshal>
<json library="Jackson" unmarshalTypeName="edu.mit.ll.mission_services.model.GenericMessage" />
</unmarshal>
<process ref="process-get-response" />
<log loggingLevel="INFO" message="end - rest-get" />
</route>
Немного другой способ:
<dataFormats>
<json id="jackson-format" library="Jackson"
unmarshalTypeName="edu.mit.ll.mission_services.model.GenericMessage" />
</dataFormats>
<route id="rest-get">
<from
uri="timer:{{http-client.timers.http-get.name}}?delay={{http-client.timers.http-get.start-delay}}&fixedRate=true&period={{http-client.timers.http-get.period}}&repeatCount={{http-client.timers.http-get.repeat-count}}" />
<log loggingLevel="INFO" message="start - rest-get" />
<to uri="rest:get:{{http-client.endpoints.http-get}}" />
<unmarshal>
<custom ref="jackson-format" />
</unmarshal>
<process ref="process-get-response" />
<log loggingLevel="INFO" message="end - rest-get" />
</route>
Оба эти работать, но это кажется проблемой (ну, скорее досадно), если бы у меня была ситуация, когда у меня были десятки (или сотни) определений классов типов сообщений. Означает ли это, что мне нужно будет создать формат данных для каждого типа? Разве нет лучшего способа?