關注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._的導入是生成實例的一種便捷方式,但它並不奇蹟般地爲任何東西和所有東西創建實例。它只會使它們成爲用該導入文件中定義的案例類。 –