是否可以从通用案例 class 创建编解码器提供程序?

Is it possible to create a Codec Provider from a generic case class?

我正在尝试创建一个通用函数,它从给定的通用案例 class 中生成 CodecProvider

BSON macro documentation没有给出任何例子。

This (unanswered) SO question 类似,但是我对为给定类型参数枚举所有可能的编解码器不感兴趣。另外,我的问题不涉及类型界限或类型差异。

这是一个无法编译的最小代码示例。

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

我希望 barCodecProvider 能够编译,但它没有。

上面的代码抛出的编译错误是class Bar takes type parameters,这很让人困惑,因为我已经通过泛型[=13]的签名明确地将类型参数T提供给了Bar =] 函数。我有打字相关的语法错误吗?错误是否表示我使用 mongo-scala-driver 不正确?

虽然可以通过隐式查找与 circe 等其他库一起使用。 org.mongodb.scala.bson.codecs.Macros 似乎是不可能的,因为没有 Macro 函数接受参数。

但是如果你知道如何制作 Codec,你可以自己动手做。

编解码器似乎是一个简单的特征,有 3 个方法 encode decodegetEncoderClass

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]

这是一个简单的示例,但它让您了解了可以做什么。 使用宏生成简单的实例,并将这些实例与使用隐含函数的函数组合起来,以自动获取正确的实例。