我写了一个类似于this one的自定义处理器。特别是,处理器采用InputDto并返回json。在Q& A的指导下,我的自定义处理器有一个带有以下内容的application.properties文件:
spring.cloud.stream.bindings.input.content-type=application/x-java-object;com.company.InputDto
spring.cloud.stream.bindings.output.content-type=application/json
从this Q&A我用这一行创建了一个spring.integration.properties
文件:
spring.integration.readOnly.headers=contentType
我正在进行自动化集成测试。到目前为止一切都很好。
我在SCDF shell中创建了一个包含处理器的流。 time
和httpclient
效果很好,因此我没有为这些显示详细的参数。在这里添加了换行符&在整个可读性方面。
stream create --name test --definition "time <args>
| httpclient <args>
| splitter --expression=\"#jsonPath(payload,'$..[0:]')\"
| myprocessor
| log"
我启用了调试日志记录。 httpclient
生成包含contentType=text/plain
和有效负载的消息:
payload=[{"name":"first","url":"url1"},{"name":"second","url":"url2"}]
splitter
按日志创建两条消息(按预期方式):
message: GenericMessage [payload={name=first, url=url1},
headers={...contentType=text/plain, ... }]
message: GenericMessage [payload={name=second, url=url2},
headers={...contentType=text/plain, ... }]
我编写的自定义处理器因此异常而失败:
org.springframework.messaging.converter.MessageConversionException: Cannot
convert from [java.util.LinkedHashMap] to [com.company.InputDto] for
GenericMessage [payload={name=first, url=url1}, headers={sequenceNumber=1,
kafka_offset=xx, sequenceSize=x, correlationId=yy, id=zzz,
kafka_receivedPartitionId=0, contentType=text/plain,
kafka_receivedTopic=test.splitter, timestamp=1503591622851}]
at
org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver.resolveArgument(PayloadArgumentResolver.java:142) ~[spring-messaging-4.3.10.RELEASE.jar!/:4.3.10.RELEASE]
....
我不确定LinkedHashMap
的来源。我尝试将application.properties文件更改为:
spring.cloud.stream.bindings.input.content-type=application/json;com.company.InputDto
但没有帮助。我也尝试过添加
--spring.cloud.stream.bindings.output.contentType='application/json'
在创建流时splitter
(遵循sample app中的路线),但仍然会获得例外。
我花了好几个小时,却看不到我错过的东西。感谢任何帮助。
我的自定义处理器使用Spring Cloud Dalston.SR3。我使用的是SCDF Server和shell 1.3.0.M1。使用Kafka活页夹。
更新,更多信息。我查看了Splitter启动器中的代码,并编写了一个小测试用例来模拟它正在做什么。
final ExpressionEvaluatingSplitter splitter = new ExpressionEvaluatingSplitter(
new SpelExpressionParser().parseExpression(
"T(com.jayway.jsonpath.JsonPath).read(payload, '$..[0:]')"));
final PollableChannel channel = new QueueChannel();
splitter.setOutputChannel(channel);
splitter.handleMessage(new GenericMessage<Object>(
"[{\"name\":\"first\",\"url\":\"url1\"},
{\"name\":\"second\",\"url\":\"url2\"}]"));
final Message<?> message = channel.receive(10);
System.out.println("payload class: " + message.getPayload().getClass());
System.out.println("payload: " + message.getPayload());
System.out.println(channel.receive(10));
这会产生输出:
payload class: class java.util.LinkedHashMap
payload: {name=first, url=url1}
GenericMessage [payload={name=second, url=url2}, headers={sequenceNumber=2,
correlationId=xx, id=yy, sequenceSize=2, timestamp=1503609649518}]
啊哈,LinkedHashMap
!现在我只需要说服拆分器将输出发送为纯文本或json,而不是Map。
更新2.我已经能够在不使用任何自定义处理器的情况下复制此问题。
stream create --name test --definition "time <args>
| httpclient <args>
| splitter --expression=\"#jsonPath(payload,'$.[0:]')\"
--outputType=\"application/json\"
| transform --expression=\"new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(payload) != null\"
--outputType=\"application/json\"
| log"
运行时,拆分器日志文件包含此异常(删节),臭名昭着的&#34;有效负载不得为空&#34;错误:
2017-08-25 13:09:30,322 DEBUG -kafka-listener-2 o.s.i.c.DirectChannel:411 - preSend on channel 'output', message: GenericMessage [payload={name=first, url=url1}, headers={sequenceNumber=1, kafka_offset=xx sequenceSize=2, correlationId=yy, id=zz, kafka_receivedPartitionId=0, contentType=text/plain, kafka_receivedTopic=test.httpclient, timestamp=1503680970322}]
2017-08-25 13:09:30,328 ERROR -kafka-listener-2 o.s.k.l.LoggingErrorHandler:37 - Error while processing: ConsumerRecord(topic = test.httpclient, partition = 0, offset = 52606, CreateTime = 1503680967030, checksum = 2166925613, serialized key size = -1, serialized value size = 470, key = null, value = [B@6567451e)
org.springframework.messaging.MessageDeliveryException: failed to send Message to channel 'output'; nested exception is java.lang.IllegalArgumentException: payload must not be null
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:449) ~[spring-integration-core-.3.8.RELEASE.jar!/:4.3.8.RELEASE]
看起来分割器很难将LinkedHashMap转换为JSON。有什么方法可以进行转换吗?
我还尝试将httpclient处理器的outputType设置为显式application/json
,但它似乎没有什么区别。 (在docs之后。示例显示带有shell引号的outputType值,我也尝试过没有,没有区别。)
使用命令将应用程序加载到SCDF服务器中(替换为&#39;。&#39; in bit-ly所以SO会接受链接)
app import --uri http://bit-ly/Bacon-RELEASE-stream-applications-kafka-10-maven
注意到一些事情。调试日志记录始终显示内容类型为text/plain
,因此它似乎没有获取我明确设置的内容类型。此外,如果我删除transform
处理器,错误就会消失。我在日志中看到了数据,但没有看到JSON格式,只是这样:
{name=first, url=url1}
答案 0 :(得分:0)
如果您愿意,可以尝试设置拆分器的输出内容类型,并删除输入处理器的任何contentType定义。 JSON-&gt; POJO应该来自邮件头。
答案 1 :(得分:0)
我能够通过显式设置inputType和outputType来实现纯Spring流和包含我自定义处理器的流的工作。
stream create --name test --definition "time
| httpclient <args> --outputType=\"application/json\"
| splitter --expression=\"#jsonPath(payload,'$.[0:]')\"
--inputType=\"application/json\"
--outputType=\"application/json\"
| myprocessor
--inputType=\"application/json\"
--outputType=\"application/json\"
| log"
Gary Russell提到此问题已在Spring Cloud Stream Ditmars.M2(1.3.0.M2)中得到纠正。