I am an author of Subset (both 1.x and 2).
The README states that you need to have Field[T]
per every T
you would like to read (it's under "deserialization" section)
Just a side note. Frankly I don't find very logical to name a deserializer for
MenuItem
to bejodaDateTime
.
Anyway Field[T]
must translate from vanilla BSON types to your T
. BSON cannot store MenuItem
natively, see native BSON types here
But certainly the main problem is that you have a recursive data structure, so your "serializer" (BsonWritable
) and "deserializer" (Field
) must be recursive as well. Subset has implicit serializer/deserializer for List[T]
, but they require you to provide those for MenuItem
: recursion.
To keep things short, I shall demonstrate you how you would write something like that for simpler "case class".
Suppose we have
case class Rec(id: Int, children: Option[List[Rec]])
Then the writer may look like
object Rec {
implicit object asBson extends BsonWritable[Rec] {
override def apply(rec: Rec) =
Some( DBO("id" -> rec.id, "children" -> rec.children)() )
}
Here, when you are writing rec.children
into "DBObject", BsonWriteable[Rec]
is being used and it requires "implicit" Field[Rec]
in turn. So, this serializer is recursive.
As of the deserializer, the following will do
import DocParser._
implicit lazy val recField = Field({ case Doc(rec) => rec })
lazy val Doc: DocParser[Rec] =
get[Int]("id") ~ get[List[Rec]]("children").opt map {
case id ~ children => new Rec(id, children)
}
}
These are mutually recursive (remember to use lazy val
!)
You would use them like so:
val dbo = DBO("y" -> Rec(123, Some(Rec(234, None) :: Nil))) ()
val Y = DocParser.get[Rec]("y")
dbo match {
case Y(doc) => doc
}