2017-03-29 7 views
0

CaseClassオブジェクトの構築にLabelledGenericsを使用する前に、正しい順序でHListを取得できない点を除いて、これを実装しています。Scalaシェイプレスを使用して[String、Array Byte]をCaseClassに変換する

何今作品が機能しない何

case class Foo(a:int, b:String) 
val serializedRecord("a" -> somebytes, "b" -> someotherbytes) 
val caseClassObject = HBaseSerDe[Foo].deserialize(serializedRecord) 

では、次のとおりです。私が読んだものから、

case class Foo(a:int, b:String) 
val serializedRecord(x -> value1 ,"a" -> somebytes, "b" -> someotherbytes, z -> value2) 
//expected Foo(somebytes, someotherbytes) 
val caseClassObject = HBaseSerDe[Foo].deserialize(serializedRecord) 

私は私のHlistは前に整理得るために位置合わせし、交差を使用することになっていますデシリアライズしていますが、すべての例で、次のようなものを使用しています(github.com/underscoreio/shapeless-guideから取得)

implicit def genericMigration[ 
    A, B, 
    ARepr <: HList, BRepr <: HList, 
    Unaligned <: HList 
](
    implicit 
    aGen : LabelledGeneric.Aux[A, ARepr], 
    bGen : LabelledGeneric.Aux[B, BRepr], 
    inter : hlist.Intersection.Aux[ARepr, BRepr, Unaligned], 
    align : hlist.Align[Unaligned, BRepr] 
): Migration[A, B] = new Migration[A, B] { 
    def apply(a: A): B = 
     bGen.from(align.apply(inter.apply(aGen.to(a)))) 
} 

しかし、私はCaseClass Aを持っておらず、その表現をその場で構築する方法を理解できませんでした。現在のコードは以下のとおりです。

implicit val hNilEncoder = instance[HNil](
    r => Map(), 
    l => HNil 
) 

    implicit def hListSerDe[ 
     Key <: Symbol, 
     H, 
     T <: HList 
    ](
    implicit 
    key: Witness.Aux[Key], 
    headSerDe: HBaseFieldShapelessSerDe[H], 
    tailSerDe: HBaseRecordShapelessSerDe[T] 
    ): HBaseRecordShapelessSerDe[FieldType[Key, H] :: T] = 
    instance[FieldType[Key, H] :: T](
     hList => { 
     Map(key.value.name -> headSerDe.serialize(hList.head)) ++ tailSerDe.serialize(hList.tail) 
     }, 
     byteList => { 
     field[Key](headSerDe.deSerialize(byteList.head._2)) :: tailSerDe.deSerialize(byteList.tail) 
     } 
    ) 

    implicit def caseClassSerDe[ 
     TargetType, 
     L <: HList 
    ](
    implicit 
    genRepr: LabelledGeneric.Aux[TargetType, L], 
    hListSerDe: HBaseRecordShapelessSerDe[L] 
    ): HBaseRecordShapelessSerDe[TargetType] = 
    instance[TargetType](
     hList => { 
     hListSerDe.serialize(genRepr.to(hList)) 
     }, 
     byteList => { 

     genRepr.from(hListSerDe.deSerialize(byteList)) 
     } 
    ) 


    def apply[RecordSerDeType](implicit serde: HBaseRecordShapelessSerDe[RecordSerDeType]): HBaseRecordShapelessSerDe[RecordSerDeType] = serde 

    def instance[RecordSerDeType](serializeFunc: RecordSerDeType => Map[String, Array[Byte]], deserializeFunc: Map[String, Array[Byte]] => RecordSerDeType): HBaseRecordShapelessSerDe[RecordSerDeType] = { 
    new HBaseRecordShapelessSerDe[RecordSerDeType] { 
     override def serialize(value: RecordSerDeType): Map[String, Array[Byte]] = serializeFunc(value) 

     override def deSerialize(value: Map[String, Array[Byte]]): RecordSerDeType = deserializeFunc(value) 
    } 
    } 

答えて

0

私はこれまでにこれを解決しましたが、それは後世の解決策です。後見ではかなりシンプルでした。

import shapeless.labelled.FieldType 
import shapeless.{::, Generic, HList, HNil, LabelledGeneric, Witness} 
import shapeless.labelled.{FieldType, _} 


object MapToCaseClass { 


    sealed trait RecordConverter[V, TargetType] { 
    def convert(rawRecord: Map[String,V]):TargetType 
    } 


    implicit def hNilConverter[V]:RecordConverter[V, HNil] = instance[V,HNil](
    _ => HNil 
) 

    implicit def hListConverter[V, H, T <: HList, K <: Symbol](implicit fieldConverter: FieldConverter[V, H], tailConverter:RecordConverter[V, T], key: Witness.Aux[K]):RecordConverter[V, FieldType[K, H] :: T] = 
    instance[V, FieldType[K, H] :: T](
     fieldMap => { 
     val currentKeyName = key.value.name 
     val value = fieldMap(currentKeyName) 
     val mapRest = fieldMap.filterKeys(_!=currentKeyName) 
     //TODO: Add a way for default value providing, Option handling and nested HLists for in case no value was found 
     field[K](fieldConverter.convert(value)) :: tailConverter.convert(mapRest) 
     } 
    ) 

    implicit def caseClassConverter[V, C, CRepr <: HList](implicit caseClassGenRepr: LabelledGeneric.Aux[C,CRepr], recordConverter:RecordConverter[V, CRepr]):RecordConverter[V, C] = 
    instance[V, C](
     fieldMap => { 
     caseClassGenRepr.from(recordConverter.convert(fieldMap)) 
     } 
    ) 

    private[this] def instance[V, T](func: Map[String,V] => T) : RecordConverter[V, T] = new RecordConverter[V, T] { 
    override def convert(rawRecord: Map[String, V]): T = func(rawRecord) 
    } 

    //summoner 
    def apply[V, T](implicit recordConverter: RecordConverter[V, T]):RecordConverter[V, T] = recordConverter 


} 
関連する問題