关注Idan Waisman答案和C4stor answer在我的副本中question我使用了Type Classes模式。为简洁起见,我仅提供用于解码json的示例代码。编码可以以完全相同的方式实现。
首先,让我们定义将用于注入JSON解码器的依赖性的特点:
trait JsonDecoder[T] {
def apply(s: String): Option[T]
}
接下来我们定义创建实例实现这一特质对象:
import io.circe.Decoder
import io.circe.parser.decode
object CirceDecoderProvider {
def apply[T: Decoder]: JsonDecoder[T] =
new JsonDecoder[T] {
def apply(s: String) =
decode[T](s).fold(_ => None, s => Some(s))
}
}
正如你可以看到apply
要求隐含的io.circe.Decoder[T]
在其调用时处于范围内。
然后我们复制io.circe.generic.auto
对象内容并创建一个性状(I制成PR有这个特征可以作为io.circe.generic.Auto
):
import io.circe.export.Exported
import io.circe.generic.decoding.DerivedDecoder
import io.circe.generic.encoding.DerivedObjectEncoder
import io.circe.{ Decoder, ObjectEncoder }
import io.circe.generic.util.macros.ExportMacros
import scala.language.experimental.macros
trait Auto {
implicit def exportDecoder[A]: Exported[Decoder[A]] = macro ExportMacros.exportDecoder[DerivedDecoder, A]
implicit def exportEncoder[A]: Exported[ObjectEncoder[A]] = macro ExportMacros.exportEncoder[DerivedObjectEncoder, A]
}
接着在包装(例如com.example.app.json
)使用JSON解码很多我们创建包对象,如果不存在,并使其扩展Auto
特点,并提供隐性返回JsonDecoder[T]
给定类型的T
:
package com.example.app
import io.circe.Decoder
package object json extends Auto {
implicit def decoder[T: Decoder]: JsonDecoder[T] = CirceDecoderProvider[T]
}
现在:
- 所有源文件在
com.example.app.json
在范围
Auto
implicits你可以得到JsonDecoder[T]
对于具有io.circe.Decoder[T]
或者它可以生成任何类型的T
d与Auto
implicits
- 你不需要仅通过改变
com.example.app.json
包对象的内容导入io.circe.generic.auto._
中的每个文件
- 可以JSON库之间进行切换。
例如,你可以切换到json4s(尽管我做了相反的事情,并从json4s切换到循环)。实现提供商JsonDecoder[T]
:
import org.json4s.Formats
import org.json4s.native.JsonMethods._
import scala.util.Try
case class Json4SDecoderProvider(formats: Formats) {
def apply[T: Manifest]: JsonDecoder[T] =
new JsonDecoder[T] {
def apply(s: String) = {
implicit val f = formats
Try(parse(s).extract[T]).toOption
}
}
}
,并更改com.example.app.json
包对象的内容:
package com.example.app
import org.json4s.DefaultFormats
package object json {
implicit def decoder[T: Manifest]: JsonDecoder[T] = Json4SDecoderProvider(DefaultFormats)[T]
}
随着类型类的模式你编译时依赖注入。这给你比运行时依赖注入更少的灵活性,但我怀疑你需要在运行时切换json解析器。
为了记录,io.circe.generic.auto._的导入是生成实例的一种便捷方式,但它并不奇迹般地为任何东西和所有东西创建实例。它只会使它们成为用该导入文件中定义的案例类。 –