Scala: convert map to case class

前端 未结 6 2070
说谎
说谎 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:06

    Here is an alternative non-boilerplate method that uses Scala reflection (Scala 2.10 and above) and doesn't require a separately compiled module:

    import org.specs2.mutable.Specification
    import scala.reflect._
    import scala.reflect.runtime.universe._
    
    case class Test(t: String, ot: Option[String])
    
    package object ccFromMap {
      def fromMap[T: TypeTag: ClassTag](m: Map[String,_]) = {
        val rm = runtimeMirror(classTag[T].runtimeClass.getClassLoader)
        val classTest = typeOf[T].typeSymbol.asClass
        val classMirror = rm.reflectClass(classTest)
        val constructor = typeOf[T].decl(termNames.CONSTRUCTOR).asMethod
        val constructorMirror = classMirror.reflectConstructor(constructor)
    
        val constructorArgs = constructor.paramLists.flatten.map( (param: Symbol) => {
          val paramName = param.name.toString
          if(param.typeSignature <:< typeOf[Option[Any]])
            m.get(paramName)
          else
            m.get(paramName).getOrElse(throw new IllegalArgumentException("Map is missing required parameter named " + paramName))
        })
    
        constructorMirror(constructorArgs:_*).asInstanceOf[T]
      }
    }
    
    class CaseClassFromMapSpec extends Specification {
      "case class" should {
        "be constructable from a Map" in {
          import ccFromMap._
          fromMap[Test](Map("t" -> "test", "ot" -> "test2")) === Test("test", Some("test2"))
          fromMap[Test](Map("t" -> "test")) === Test("test", None)
        }
      }
    }
    

提交回复
热议问题