Scala: convert map to case class

前端 未结 6 2087
说谎
说谎 2020-12-01 01:53

Let\'s say I have this example case class

case class Test(key1: Int, key2: String, key3: String)

And I have a map

myMap = M         


        
6条回答
  •  星月不相逢
    2020-12-01 02:18

    Jonathan Chow implements a Scala macro (designed for Scala 2.11) that generalizes this behavior and eliminates the boilerplate.

    http://blog.echo.sh/post/65955606729/exploring-scala-macros-map-to-case-class-conversion

    import scala.reflect.macros.Context
    
    trait Mappable[T] {
      def toMap(t: T): Map[String, Any]
      def fromMap(map: Map[String, Any]): T
    }
    
    object Mappable {
      implicit def materializeMappable[T]: Mappable[T] = macro materializeMappableImpl[T]
    
      def materializeMappableImpl[T: c.WeakTypeTag](c: Context): c.Expr[Mappable[T]] = {
        import c.universe._
        val tpe = weakTypeOf[T]
        val companion = tpe.typeSymbol.companionSymbol
    
        val fields = tpe.declarations.collectFirst {
          case m: MethodSymbol if m.isPrimaryConstructor ⇒ m
        }.get.paramss.head
    
        val (toMapParams, fromMapParams) = fields.map { field ⇒
          val name = field.name
          val decoded = name.decoded
          val returnType = tpe.declaration(name).typeSignature
    
          (q"$decoded → t.$name", q"map($decoded).asInstanceOf[$returnType]")
        }.unzip
    
        c.Expr[Mappable[T]] { q"""
          new Mappable[$tpe] {
            def toMap(t: $tpe): Map[String, Any] = Map(..$toMapParams)
            def fromMap(map: Map[String, Any]): $tpe = $companion(..$fromMapParams)
          }
        """ }
      }
    }
    

提交回复
热议问题