所以我有一个有效的实现,除非我在使用LabelledGenerics构建CaseClass对象之前无法以正确的顺序获取HList。
现在有效的是
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)
根据我的阅读,我应该使用Align和Intersect在反序列化之前对我的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 :(得分:1)
我现在解决了这个问题,这是后人的解决方案。事后看来,这非常简单。
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
}