복붙노트

[SCALA] 스칼라 : 케이스 클래스로 변환지도

SCALA

스칼라 : 케이스 클래스로 변환지도

하자 내가이 예제의 경우 클래스가 있다고 가정 해

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

그리고지도를 가지고

myMap = Map("k1" -> 1, "k2" -> "val2", "k3" -> "val3")

이 같은 코드, 뭔가의 여러 장소에서 내 경우 클래스에이지도를 변환해야합니다 :

myMap.asInstanceOf[Test]

그 일을 가장 쉬운 방법이 있을까요? 어떻게 든 이것에 대한 암시를 사용할 수 있습니까?

해결법

  1. ==============================

    1.우아하게이 일을 두 가지 방법. 먼저 당신을 위해 변환을 할 수있는 타입의 클래스를 암시 클래스 (2.10+)를 사용하기 위해 적용 취소, 두 번째를 사용하는 것입니다.

    우아하게이 일을 두 가지 방법. 먼저 당신을 위해 변환을 할 수있는 타입의 클래스를 암시 클래스 (2.10+)를 사용하기 위해 적용 취소, 두 번째를 사용하는 것입니다.

    1)는 적용 취소 이러한 변환을 작성하는 가장 간단하고 똑 바른 앞으로 방법입니다. 그것은 어떤 "마술"을하지 않습니다와 IDE를 사용하는 경우 쉽게 찾을 수 있습니다. 컴패니언 객체를 어수선하게하고 싶지 않을 수도 있습니다 장소에서 새싹 종속성에 코드를 일으킬 수 있습니다 이런 종류의 일을, 메모를 수행합니다

    object MyClass{
      def unapply(values: Map[String,String]) = try{
        Some(MyClass(values("key").toInteger, values("next").toFloat))
      } catch{
        case NonFatal(ex) => None
      }
    }
    

    어떤이처럼 사용할 수 있습니다 :

    val MyClass(myInstance) = myMap
    

    완전히 일치하지 않는 경우에 예외를 슬로우로,주의하십시오.

    타입 클래스를 사용하면 더 많은 보일러를 만들지 만 다른 경우 클래스에 적용하는 동일한 패턴을 확장 객실의 많은 수와 2) 암시 적 클래스를 수행 :

    implicit class Map2Class(values: Map[String,String]){
      def convert[A](implicit mapper: MapConvert[A]) = mapper conv (values)
    }
    
    trait MapConvert[A]{
      def conv(values: Map[String,String]): A
    }
    

    그리고 예를 들어 당신은 같은 것을 할 것입니다 :

    object MyObject{
      implicit val new MapConvert[MyObject]{
        def conv(values: Map[String, String]) = MyObject(values("key").toInt, values("foo").toFloat)
      }
    }
    

    당신이 위에서 설명했던대로 후 바로 사용할 수있는 :

    val myInstance = myMap.convert[MyObject]
    

    어떤 변환이 이루어지지 할 수있는 경우 예외를 throw. 어떤 개체에 맵 [문자열, 문자열] 간의 변환이 패턴을 사용하여 또 다른 암시적인 (그리고 암시 적 범위로한다.) 필요

  2. ==============================

    2.여기서 스칼라 리플렉션을 사용하는 다른 비 상용구 방법 (상기 스칼라 2.10)이며, 별도로 컴파일 된 모듈을 필요로하지 않는다 :

    여기서 스칼라 리플렉션을 사용하는 다른 비 상용구 방법 (상기 스칼라 2.10)이며, 별도로 컴파일 된 모듈을 필요로하지 않는다 :

    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)
        }
      }
    }
    
  3. ==============================

    3.조나단 차우는 구현이 동작을 일반화하고 보일러를 제거 (스칼라 2.11을 위해 설계) 스칼라 매크로를.

    조나단 차우는 구현이 동작을 일반화하고 보일러를 제거 (스칼라 2.11을 위해 설계) 스칼라 매크로를.

    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)
          }
        """ }
      }
    }
    
  4. ==============================

    4.이 코드를 사랑하지 않아,하지만 난 당신이 튜플로지도 값을 가져 다음의 경우 클래스의 tupled 생성자를 사용할 수있는 경우이 가능 같아요. 즉 다음과 같이 보일 것입니다 :

    이 코드를 사랑하지 않아,하지만 난 당신이 튜플로지도 값을 가져 다음의 경우 클래스의 tupled 생성자를 사용할 수있는 경우이 가능 같아요. 즉 다음과 같이 보일 것입니다 :

    val myMap = Map("k1" -> 1, "k2" -> "val2", "k3" -> "val3")    
    val params = Some(myMap.map(_._2).toList).flatMap{
      case List(a:Int,b:String,c:String) => Some((a,b,c))
      case other => None
    }    
    val myCaseClass = params.map(Test.tupled(_))
    println(myCaseClass)
    

    당신은 확실히 값 목록 정확히 3 개 요소이며, 그들이 올바른 종류가 있는지 확인하기 위해주의해야합니다. 그렇지 않다면, 당신은 대신 없음으로 끝낼. 나는이 위대한하지 말했지만, 그것이 가능하다는 것을 보여주고있다.

  5. ==============================

    5.당신이 스칼라에 대해 잭슨을 사용하는 경우에, 나를 위해 잘 작동합니다 :

    당신이 스칼라에 대해 잭슨을 사용하는 경우에, 나를 위해 잘 작동합니다 :

    def from[T](map: Map[String, Any])(implicit m: Manifest[T]): T = {
      val mapper = new ObjectMapper() with ScalaObjectMapper
      mapper.convertValue(map)
    }
    

    POJO에지도 <문자열, 문자열> 변환 :에서 참조

  6. ==============================

    6.

    commons.mapper.Mappers.mapToBean[CaseClassBean](map)
    

    세부 : https://github.com/hank-whu/common4s

  7. from https://stackoverflow.com/questions/20684572/scala-convert-map-to-case-class by cc-by-sa and MIT license