Reputation: 75
I'm using Scrooge to generate classes. They look something like this, here's an example:
object Flags extends ThriftStructCodec3[Flags] {
private val NoPassthroughFields = immutable$Map.empty[Short, TFieldBlob]
val Struct = new TStruct("Flags")
val IsDangerousField = new TField("isDangerous", TType.BOOL, 1)
val IsDangerousFieldManifest = implicitly[Manifest[Boolean]]
val IsWildField = new TField("isWild", TType.BOOL, 2)
val IsWildFieldManifest = implicitly[Manifest[Boolean]]
def apply(
isDangerous: Option[Boolean] = None,
isWild: Option[Boolean] = None
): Flags =
new Immutable(
isDangerous,
isWild
)
def unapply(_item: Flags): Option[scala.Product2[Option[Boolean], Option[Boolean]]] = Some(_item)
object Immutable extends ThriftStructCodec3[Flags] {
override def encode(_item: Flags, _oproto: TProtocol) { _item.write(_oproto) }
override def decode(_iprot: TProtocol): Flags = Flags.decode(_iprot)
}
/**
* The default read-only implementation of Flags. You typically should not need to
* directly reference this class; instead, use the Flags.apply method to construct
* new instances.
*/
class Immutable(
val isDangerous: Option[Boolean],
val isWild: Option[Boolean],
override val _passthroughFields: immutable$Map[Short, TFieldBlob]
) extends Flags {
def this(
isDangerous: Option[Boolean] = None,
isWild: Option[Boolean] = None
) = this(
isDangerous,
isWild,
Map.empty
)
}
}
trait Flags
extends ThriftStruct
with scala.Product2[Option[Boolean], Option[Boolean]]
with java.io.Serializable
{
import Flags._
def isDangerous: Option[Boolean]
def isWild: Option[Boolean]
def _passthroughFields: immutable$Map[Short, TFieldBlob] = immutable$Map.empty
def _1 = isDangerous
def _2 = isWild
override def productArity: Int = 2
override def productElement(n: Int): Any = n match {
case 0 => this.isDangerous
case 1 => this.isWild
case _ => throw new IndexOutOfBoundsException(n.toString)
}
override def productPrefix: String = "Flags"
}
The aim is to generate from these classes a nested map using Shapeless, do some operation on it and then convert the map back to thrift generated classes.
Using Converting nested case classes to nested Maps using Shapeless and Converting Map[String,Any] to a case class using Shapeless I managed to put together a project which works fine with basic case classes. On top of the examples provided in the stack overflow responses I have also implemented implicits for Option[A].
Now, because Scrooge is not generating proper case classes I was trying to use the Immutable class instead (e.g. Flags.Immutable
). Doing this means I have to define implicits for all the thrift classes to convert them to NameOfClass.Immutable
. So far so good.
But I have 2 things I seem to not get right (the full implementation can be found in the ClassToMap.scala
file):
(1) When generating the map from thrift classes the Option implicit seems to be ignored.
implicit def hconsToMapRecOption[K <: Symbol, V, R <: HList, T <: HList]
(implicit
wit: Witness.Aux[K],
gen: LabelledGeneric.Aux[V, R],
tmrT: Lazy[ToMapRec[T]],
tmrH: Lazy[ToMapRec[R]]
): ToMapRec[FieldType[K, Option[V]] :: T] = new ToMapRec[FieldType[K, Option[V]] :: T] {
override def apply(l: FieldType[K, Option[V]] :: T): Map[String, Any] = {
tmrT.value(l.tail) + (wit.value.name -> l.head.map(value => tmrH.value(gen.to(value))))
}
}
(2) When dealing with thrift unions my implicit is not being used.
implicit def hconsToMapRecGoatData[K <: Symbol, R <: HList, T <: HList]
(implicit
wit: Witness.Aux[K],
gen: LabelledGeneric.Aux[MyGoat, R],
tmrT: Lazy[ToMapRec[T]],
tmrH: Lazy[ToMapRec[R]]
): ToMapRec[FieldType[K, MyGoatData] :: T] = new ToMapRec[FieldType[K, MyGoatData] :: T] {
override def apply(l: FieldType[K, MyGoatData] :: T): Map[String, Any] = {
tmrT.value(l.tail) + (wit.value.name -> tmrH.value(gen.to(l.head.goat)))
}
}
I haven't spent so much time looking at the map to class implementation, but I assume it should mirror the class to map one.
Upvotes: 4
Views: 308