All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.findify.flinkpb.ProtobufSerializer.scala Maven / Gradle / Ivy

The newest version!
package io.findify.flinkpb

import com.google.protobuf.{GeneratedMessageV3, Parser}
import io.findify.flinkpb.Codec.{JavaCodec, ScalaCodec}
import io.findify.flinkpb.ProtobufSerializer.{JavaConfigSnapshot, ScalaConfigSnapshot}
import org.apache.flink.api.common.typeutils.{TypeSerializer, TypeSerializerSchemaCompatibility, TypeSerializerSnapshot}
import org.apache.flink.api.java.typeutils.runtime.{DataInputViewStream, DataOutputViewStream}
import org.apache.flink.core.memory.{DataInputView, DataOutputView}
import org.apache.flink.util.InstantiationUtil
import scalapb.{GeneratedMessage, GeneratedMessageCompanion}

case class ProtobufSerializer[T](codec: Codec[T]) extends TypeSerializer[T] {

  override def isImmutableType: Boolean       = true
  override def duplicate(): TypeSerializer[T] = this
  override def createInstance(): T            = codec.defaultInstance
  override def copy(from: T): T               = from
  override def copy(from: T, reuse: T): T     = from
  override def getLength: Int                 = -1

  override def serialize(record: T, target: DataOutputView): Unit = {
    codec.writeTo(new DataOutputViewStream(target), record)
  }

  override def deserialize(source: DataInputView): T = {
    codec.parseFrom(new DataInputViewStream(source))
  }

  override def deserialize(reuse: T, source: DataInputView): T =
    deserialize(source)

  override def copy(source: DataInputView, target: DataOutputView): Unit =
    serialize(deserialize(source), target)

  override def snapshotConfiguration(): TypeSerializerSnapshot[T] = codec match {
    case s: ScalaCodec[_] => new ScalaConfigSnapshot(s).asInstanceOf[TypeSerializerSnapshot[T]]
    case j: JavaCodec[_]  => new JavaConfigSnapshot(j).asInstanceOf[TypeSerializerSnapshot[T]]
  }
}

object ProtobufSerializer {

  class ScalaConfigSnapshot[T <: GeneratedMessage]() extends TypeSerializerSnapshot[T] {
    var codec: ScalaCodec[T] = _
    def this(c: ScalaCodec[T]) = {
      this()
      codec = c
    }

    override def getCurrentVersion: Int = 1

    override def readSnapshot(readVersion: Int, in: DataInputView, userCodeClassLoader: ClassLoader): Unit = {
      codec = ScalaCodec(
        companion = InstantiationUtil
          .resolveClassByName[GeneratedMessageCompanion[T]](in, userCodeClassLoader)
          .getField("MODULE$")
          .get(null)
          .asInstanceOf[GeneratedMessageCompanion[T]],
        clazz = InstantiationUtil.resolveClassByName[T](in, userCodeClassLoader)
      )
    }

    override def writeSnapshot(out: DataOutputView): Unit = {
      out.writeUTF(codec.companion.getClass.getName)
      out.writeUTF(codec.clazz.getName)
    }

    override def restoreSerializer(): TypeSerializer[T] = new ProtobufSerializer[T](codec)

    override def resolveSchemaCompatibility(newSerializer: TypeSerializer[T]): TypeSerializerSchemaCompatibility[T] =
      TypeSerializerSchemaCompatibility.compatibleAsIs()
  }

  class JavaConfigSnapshot[T <: GeneratedMessageV3]() extends TypeSerializerSnapshot[T] {
    var codec: JavaCodec[T] = _
    def this(c: JavaCodec[T]) = {
      this()
      codec = c
    }

    override def getCurrentVersion: Int = 1

    override def readSnapshot(readVersion: Int, in: DataInputView, userCodeClassLoader: ClassLoader): Unit = {
      val clazz       = InstantiationUtil.resolveClassByName[T](in, userCodeClassLoader)
      val constructor = clazz.getDeclaredConstructor()
      constructor.setAccessible(true)
      codec = JavaCodec(constructor.newInstance(), clazz)
    }

    override def writeSnapshot(out: DataOutputView): Unit = {
      out.writeUTF(codec.clazz.getName)
    }

    override def restoreSerializer(): TypeSerializer[T] = new ProtobufSerializer[T](codec)

    override def resolveSchemaCompatibility(newSerializer: TypeSerializer[T]): TypeSerializerSchemaCompatibility[T] =
      TypeSerializerSchemaCompatibility.compatibleAsIs()
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy