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

com.sksamuel.avro4s.ScalaEnums.scala Maven / Gradle / Ivy

//package com.sksamuel.avro4s
//import magnolia.{SealedTrait, Subtype}
//import org.apache.avro.generic.{GenericData, GenericEnumSymbol}
//import org.apache.avro.{Schema, SchemaBuilder}
//
//import scala.reflect.runtime.universe
//import scala.collection.JavaConverters._
//
//object ScalaEnums {
//
//  def encoder[T](ctx: SealedTrait[Encoder, T]): Encoder[T] = create[Encoder, T](ctx, new EnumEncoder[T](_))
//
//  def decoder[T](ctx: SealedTrait[Decoder, T]): Decoder[T] = create[Decoder, T](ctx, new EnumDecoder[T](_))
//
//  private type Builder[Typeclass[_], T] = CodecData[Typeclass, T] => Typeclass[T]
//
//  private def create[Typeclass[_], T](ctx: SealedTrait[Typeclass, T], builder: Builder[Typeclass, T]): Typeclass[T] = {
//    val subtypes: Seq[Subtype[Typeclass, T]] = sortedSubtypes(ctx)
//    val schema: Schema = buildSchema(ctx, subtypes)
//
//    val symbolForSubtype: Map[Subtype[Typeclass, T], AnyRef] = subtypes.zipWithIndex.map {
//      case (st, i) => st -> GenericData.get.createEnum(schema.getEnumSymbols.get(i), schema)
//    }.toMap
//
//    val runtimeMirror = universe.runtimeMirror(Thread.currentThread().getContextClassLoader)
//    val valueForSymbol: Map[String, T] =
//      subtypes.zipWithIndex.map {
//        case (st, i) =>
//          val module = runtimeMirror.staticModule(st.typeName.full)
//          val caseObject = runtimeMirror.reflectModule(module.asModule).instance.asInstanceOf[T]
//          schema.getEnumSymbols.get(i) -> caseObject
//      }.toMap
//
//    val data =
//      new CodecData[Typeclass, T](ctx, symbolForSubtype, valueForSymbol, SchemaFor[T](schema, DefaultFieldMapper))
//    builder(data)
//  }
//
//  private class EnumDecoder[T](data: CodecData[Decoder, T]) extends Decoder[T] {
//    val schemaFor = data.schemaFor
//
//    import data._
//
//    def decode(value: Any): T = value match {
//      case e: GenericEnumSymbol[_] => valueForSymbol(e.toString)
//      case s: String               => valueForSymbol(s)
//    }
//
//    override def withSchema(schemaFor: SchemaFor[T]): Decoder[T] = {
//      validateSchema(schemaFor, data.valueForSymbol)
//      super.withSchema(schemaFor)
//    }
//  }
//
//  private class EnumEncoder[T](data: CodecData[Encoder, T]) extends Encoder[T] {
//    val schemaFor = data.schemaFor
//
//    import data._
//
//    def encode(value: T): AnyRef = ctx.dispatch(value)(symbolForSubtype)
//
//    override def withSchema(schemaFor: SchemaFor[T]): Encoder[T] = {
//      validateSchema(schemaFor, data.valueForSymbol)
//      super.withSchema(schemaFor)
//    }
//  }
//
//  private def validateSchema[T](schemaFor: SchemaFor[T], valueForSymbol: Map[String, T]): Unit = {
//    val newSchema = schemaFor.schema
//    if (newSchema.getType != Schema.Type.ENUM)
//      throw new Avro4sConfigurationException(s"Schema type for enum codecs must be ENUM, received $newSchema")
//    val currentSymbols = valueForSymbol.keys.toSet
//    val newSymbols = newSchema.getEnumSymbols.asScala.toSet
//    if (newSymbols != currentSymbols)
//      throw new Avro4sConfigurationException(
//        s"Enum codec symbols cannot be changed via schema; schema symbols are ${newSymbols.mkString(",")} - codec symbols are $currentSymbols")
//  }
//
//  private class CodecData[Typeclass[_], T](val ctx: SealedTrait[Typeclass, T],
//                                           val symbolForSubtype: Map[Subtype[Typeclass, T], AnyRef],
//                                           val valueForSymbol: Map[String, T],
//                                           val schemaFor: SchemaFor[T])
//
//  private def sortedSubtypes[TC[_], T](ctx: SealedTrait[TC, T]): Seq[Subtype[TC, T]] = {
//    def priority(st: Subtype[TC, T]) = new AnnotationExtractors(st.annotations).sortPriority.getOrElse(0.0f)
//    ctx.subtypes.sortWith((l, r) => priority(l) > priority(r))
//  }
//
//  def schema[Typeclass[_], T](ctx: SealedTrait[Typeclass, T]): Schema = buildSchema(ctx, sortedSubtypes(ctx))
//
//  private def buildSchema[Typeclass[_], T](ctx: SealedTrait[Typeclass, T],
//                                           sortedSubtypes: Seq[Subtype[Typeclass, T]]): Schema = {
//    val symbols = sortedSubtypes.map { sub =>
//      val nameExtractor = NameExtractor(sub.typeName, sub.annotations)
//      nameExtractor.name
//    }
//    val nameExtractor = NameExtractor(ctx.typeName, ctx.annotations)
//
//    val builder = SchemaBuilder.enumeration(nameExtractor.name).namespace(nameExtractor.namespace)
//
//    val builderWithDefault = sealedTraitEnumDefaultValue(ctx) match {
//      case Some(default) => builder.defaultSymbol(default)
//      case None          => builder
//    }
//
//    builderWithDefault.symbols(symbols: _*)
//  }
//
//  private def sealedTraitEnumDefaultValue[TC[_], T](ctx: SealedTrait[TC, T]) = {
//    val defaultExtractor = new AnnotationExtractors(ctx.annotations)
//    defaultExtractor.enumDefault.flatMap { default =>
//      ctx.subtypes.flatMap { st =>
//        if (st.typeName.short == default.toString)
//          Option(st.typeName.short)
//        else
//          None
//      }.headOption
//    }
//  }
//}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy