I am trying to make a generic function which produces a CodecProvider
from a given generic case class.
The BSON macro documentation does not give any examples of this.
This (unanswered) SO question is similar, however I am not interested in enumerating all possible codec's for a given type parameter. Also, my question does not deal with type bounds or type variances.
Here is a minimal example of the code which does not compile.
import org.mongodb.scala.bson.codecs.Macros
case class Foo(x: Int)
case class Bar[T](x: T)
def fooCodecProvider = Macros.createCodecProvider[Foo]()
// Compiles! (No generic)
def barCodecProvider[T] = Macros.createCodecProvider[Bar[T]]()
// Compile Error:(8, 70) class Bar takes type parameters
I expect the barCodecProvider
to compile, however it does not.
The compilation error thrown by the above code reads class Bar takes type parameters
which is confusing because I have clearly provided the type parameter T
to Bar
via the signature of the generic barCodecProvider
function. Do I have a typing-related syntax error? Is error a sign that I am using the mongo-scala-driver incorrectly?
While It's possible with other libraries like circe via implicit lookup.
It seems impossible with org.mongodb.scala.bson.codecs.Macros
because no Macro
function take parameters.
But you could do it your self if you know how to make a Codec
.
Codec seems to be a simple trait with 3 methods encode
decode
and getEncoderClass
implicit val fooCodec : Codec[Foo] = Macros.createCodecProvider[Foo]()
def barCodecProvider[T: ClassTag](implicit codecT : Codec[T]) = new Codec[Bar[T]] {
override def decode(reader: BsonReader, decoderContext: DecoderContext): Bar[T] = {
Bar[T](codecT.decode(reader,decoderContext))
}
override def encode(writer: BsonWriter, value: Bar[T], encoderContext: EncoderContext): Unit = {
codecT.encode(writer, value.x, encoderContext)
}
//the tricky one
override def getEncoderClass: Class[Bar[T]] = classTag[Bar[T]].runtimeClass.asInstanceOf[Class[Bar[T]]]
}
val barFooCodec : Codec[Bar[Foo]] = barCodecProvider[Foo]
It's simple example, but it's give an idea of what you can do. Use macro to generate simple instances, and composes theses instances with functions using implicits to fetch automatically the right instances.