Apache Kavka使用Java将Java中的记录序列化并在Scala中反序列化

时间:2020-11-01 05:09:46

标签: java scala apache-kafka deserialization avro

我有一个使用Java 11 / spring和apache-avro的生产者,另一方面,我有一个使用scala 2.12和akka的消费者。如果我没有记错的话,那么Avro负载应该与语言无关。但是,当我尝试在Scala使用者中获取ConsumerRecord的值时,会收到ClassCastException:

java.lang.ClassCastException: class com.example.schema.DetailsSchema cannot be cast to class com.example.schema.scala.DetailsSchema (com.example.schema.DetailsSchema and com.example.schema.scala.DetailsSchema are in unnamed module of loader 'app'

我正在使用几个插件从我的模式中生成Java和Scala类

  • “ com.commercehub.gradle.plugin.avro”版本“ 0.9.1”
  • “ com.zlad.gradle.avrohugger”版本“ 0.5.0”

对于scala类,我只是在名称空间的末尾附加一个.scala包,以避免与Java生成的类发生冲突。

  • Avro模式和Java / scala类位于使用上述插件的通用jar中。 Java类使用 com.example.schema 包生成,Scala类使用 com.example.schema.scala ,它们都扩展了org.apache.avro.specific.SpecificRecordBase < / li>
  • 我的生产者是使用spring-kafka和confluent的kafka-avro-serializer的标准Spring应用程序
  • 我的消费者是使用akka-stream-kafka的akka​​应用程序 消费者代码:

    import io.confluent.kafka.serializers.KafkaAvroDeserializer
      import org.apache.kafka.common.serialization._
    
      val kafkaAvroSerDeConfig = Map[String, Any](
        AbstractKafkaSchemaSerDeConfig.SCHEMA_REGISTRY_URL_CONFIG -> "http://localhost:8081",
        KafkaAvroDeserializerConfig.SPECIFIC_AVRO_READER_CONFIG -> true.toString
      )
    
      val kafkaConsumerSettings: ConsumerSettings[String, DetailsChema] = {
        val kafkaAvroDeserializer = new KafkaAvroDeserializer()
        kafkaAvroDeserializer.configure(kafkaAvroSerDeConfig.asJava, false)
        val deserializer = kafkaAvroDeserializer.asInstanceOf[Deserializer[DetailsChema]]
    
        ConsumerSettings(system, new StringDeserializer, deserializer)
          .withBootstrapServers("localhost:9092")
          .withGroupId("xt-collector")
          .withProperties((ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "true"),
            (ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "5000"),
            (ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"))
      }
    
      val control = Consumer
        .plainSource(kafkaConsumerSettings, Subscriptions.topics("details"))
        .map(msg => {
          try {
            val details = msg.value() // HERE I get the class cast exception
            // java.lang.ClassCastException: class com.example.schema.DetailsSchema cannot be cast to class com.example.schema.scala.DetailsSchema (com.example.schema.DetailsSchema and com.example.schema.scala.DetailsSchema are in unnamed module of loader 'app'
            log.info(s"Received ${details._id} to sink into mongo/elastic")
            details
          } catch {
            case e: Exception => log.error("Error while deserializing details", e)
              e.printStackTrace()
          }
        })
    //    .via(detailsCollection.flow) Just sink into mongo/elastic
        .recover {
          case t : Throwable => log.error("Error while storing in mongo/elastic", t)
        }
        .toMat(Sink.seq)(DrainingControl.apply)
        .run()

我的问题是:是否可以在Java中生成Avro记录并在另一侧使用Scala案例类反序列化,如果两者均从同一架构生成并扩展SpecificRecordBase?

0 个答案:

没有答案