用于嵌套案例类的Scala宏以Map和其他方式

时间:2015-07-21 00:16:16

标签: scala scala-macros

我想将任何案例类转换为 Map [String,Any] ,例如:

case class Person(name:String, address:Address)
case class Address(street:String, zip:Int)

val p = Person("Tom", Address("Jefferson st", 10000))
val mp = p.asMap 
//Map("name" -> "Tom", "address" -> Map("street" -> "Jefferson st", "zip" -> 10000))
val p1 = mp.asCC[Person]
assert(p1 === p)

可能的重复: 这是一个带有反思答案的question。 这是question(从案例类转换为地图(没有嵌套)

我还发现如何为一个没有任何嵌套case类的case claas做这个,这里是来自here的代码:

package macros
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.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.companion

    val fields = tpe.decls.collectFirst {
      case m: MethodSymbol if m.isPrimaryConstructor => m
    }.get.paramLists.head

    val (toMapParams, fromMapParams) = fields.map { field =>
      val name = field.asTerm.name
      val key = name.decodedName.toString
      val returnType = tpe.decl (name).typeSignature

      (q"$key -> t.$name", q"map($key).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)
      }
    """ }
  }
}

另外值得一提的是Play Json库和ReactiveMongo Bson库做同样的事情,但那些项目真的很难理解如何做到这一点。

0 个答案:

没有答案