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

avro4k.Avro4kGenericRecordCodec.kt Maven / Gradle / Ivy

package io.toolisticon.kotlin.avro.serialization.avro4k

import com.github.avrokotlin.avro4k.Avro
import com.github.avrokotlin.avro4k.decodeFromGenericData
import com.github.avrokotlin.avro4k.encodeToGenericData
import io.toolisticon.kotlin.avro.codec.AvroCodec
import io.toolisticon.kotlin.avro.codec.AvroCodec.GenericRecordDecoder
import io.toolisticon.kotlin.avro.codec.AvroCodec.GenericRecordEncoder
import io.toolisticon.kotlin.avro.model.wrapper.AvroSchema
import io.toolisticon.kotlin.avro.serialization.cache.AvroCache
import io.toolisticon.kotlin.avro.value.AvroSchemaCompatibilityMap
import kotlinx.serialization.ExperimentalSerializationApi
import org.apache.avro.generic.GenericRecord
import kotlin.reflect.KClass

/**
 * Provides [GenericRecordDecoder] and [GenericRecordEncoder] using avro4k.
 */
@OptIn(ExperimentalSerializationApi::class)
class Avro4kGenericRecordCodec(
  private val avro4k: Avro,
  private val serializerCache: AvroCache.SerializerByClassCache,
  private val schemaCache: AvroCache.SchemaByClassCache,
  private val kclassCache: AvroCache.ClassBySchemaCache,
  private val compatibilityCache: AvroSchemaCompatibilityMap
) {

  /**
   * @return a [AvroCodec.GenericRecordEncoder] based on [Avro.encodeToGenericData].
   */
  fun  encoder(): GenericRecordEncoder = GenericRecordEncoder { data ->
    val klass: KClass = data::class
    val serializer = serializerCache[klass]
    val writerSchema = schemaCache[klass]

    avro4k.encodeToGenericData(writerSchema.get(), serializer, data) as GenericRecord
  }

  /**
   * Looks up class and redirects to [Avro4kGenericRecordCodec.decoder(KClass)].
   *
   * @return a [AvroCodec.GenericRecordDecoder] based on [Avro.decodeFromGenericData].
   */
  fun  decoder() = GenericRecordDecoder { record ->
    val writerSchema = AvroSchema(record.schema)
    val readerKlass: KClass = kclassCache[writerSchema]

    decoder(readerKlass).decode(record)
  }

  /**
   * Reader class can be passed in to avoid additional lookup and avoid type erasure of .
   * @return a [AvroCodec.GenericRecordDecoder] based on [Avro.decodeFromGenericData].
   */
  fun  decoder(readerKlass: KClass) = GenericRecordDecoder { record ->
    val writerSchema = AvroSchema(record.schema)

    val kserializer = serializerCache[readerKlass]
    val readerSchema = schemaCache[readerKlass]
    val compatibility = compatibilityCache.compatibleToReadFrom(writerSchema, readerSchema)

    require(compatibility.isCompatible) { "Reader/writer schema are incompatible." }

    avro4k.decodeFromGenericData(writerSchema = writerSchema.get(), deserializer = kserializer, record)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy