尝试序列化Avro SpecificRecords列表并使用@Splitter对其进行拆分时{Message44version}

时间:2018-08-23 21:02:31

标签: groovy rabbitmq avro spring-cloud-stream

我有一个带有RabbitMQ活页夹的Spring Cloud Stream(Elmhurst版本)拆分器。我正在尝试对其进行更新,以便它将对负载使用Avro模式。我遇到了一个转换异常,这使得它似乎没有被调用Avro转换器,并且JSON转换器接收了消息并对其进行了触发。

  

由以下原因引起:org.springframework.messaging.converter.MessageConversionException:无法编写JSON:不是地图:{“ type”:“ record”,“ name”:“ SkinnyMessage”,“ namespace”:“ com.example .avro“,” doc“:”用于传递对消息对象的引用的轻消息“,”字段“:[{” name“:” id“,” type“:” string“},{” name“:” guid“ ,“” type“:” string“}]}(通过参考链:com.example.avro.SkinnyMessage [” schema“]-> org.apache.avro.Schema $ RecordSchema [” valueType“]);嵌套的异常是com.fasterxml.jackson.databind.JsonMappingException:不是映射:{“ type”:“ record”,“ name”:“ SkinnyMessage”,“ namespace”:“ com.example.avro”,“ doc”: “用于传递对消息对象的引用的轻消息”,“字段”:[{“名称”:“ id”,“类型”:“字符串”},{“名称”:“ guid”,“类型”:“字符串” }]}(通过参考链:com.example.avro.SkinnyMessage [“ schema”]-> org.apache.avro.Schema $ RecordSchema [“ valueType”])

我已经确认可以使用生成的Avro类(maven-avro插件)创建对象并将其序列化到磁盘,因此该部分似乎正确。我已经将项目从Groovy转换为Java,但仍然遇到相同的错误,因此我认为也可以排除。

以下是Avro模式:

{
  "namespace": "com.example.avro",
  "type": "record",
  "name": "SkinnyMessage",
  "doc": "Light message for passing references to Message objects",
  "fields": [
    {
      "name": "id",
      "type": "string"
    },
    {
      "name": "guid",
      "type": "string"
    }
  ]
}

以及课程的相关部分:

@EnableBinding(Processor.class)
@EnableSchemaRegistryClient
class PagingQueryProcessorApplication {
    @Timed(value = 'paging.query')
    @Splitter(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
    List<SkinnyMessage> queryExecutor(def trigger){
        log.debug 'Building query'
        def query = queryConfiguration.buildQuery().toUriString()

        log.info "Executing query: ${query}"
        def response = service.getRecordings(query)

        log.info "Returning response collection: ${response.body.content.size()}"
        // We build a slim notification on each of the query responses
        def skinnyMessages = response.body.content.collect{
            new SkinnyMessage(it.getLink('self').getHref(), it.content.guid)
        }
        skinnyMessages
    }
...
}

编辑:当我逐步调试时,可以看到AvroSchemaRegistryClientMessageConverter未能通过canConvertTo(payload, headers)调用,因为标头中的mimeTypeapplication/json而不是application/*+avro ,因此它将继续尝试其余的转换器链。

1 个答案:

答案 0 :(得分:0)

如果我生成一条消息并在其上设置avro content-type标头,那似乎行得通,但这似乎是一种hack。

List<Message<SkinnyMessage>> skinnyMessages = response.body.content.collect{
    MessageBuilder.withPayload(
            new SkinnyMessage(it.getLink('self').getHref(), it.content.recordingGuid))
            .setHeader('contentType', 'application/*+avro')
            .build()
}

创建在RabbitMQ UI中看起来正确的消息:

  

contentType:application / vnd.skinnymessage.v1 + avro   相关ID:f8be74d6-f780-efcc-295d-338a8b7f2ea0   content_type:应用程序/八位字节流   有效载荷   96个字节   编码:字符串

     

thttps://example.com/message/2597061H9a688e40-3e30-4b17-80e9-cf4f897e8a91

但是,如果我正确理解了文档,则应该从application.yml:中透明地进行设置(如Schema Registry Samples):

spring: cloud: stream: bindings: output: contentType: application/*+avro