带有泛型的 Scala Circe
Scala Circe with generics
我正在尝试使用 scala json 库 Circe,将其包装在一个简单的特征中以提供转换 to/from json 我有以下内容:
import io.circe.generic.auto._
import io.circe.parser._
import io.circe.syntax._
trait JsonConverter {
def toJson[T](t : T) : String
def fromJson[T](s: String) : T
}
case class CirceJsonConverter() extends JsonConverter{
override def toJson[T](t: T): String = t.asJson.noSpaces
override def fromJson[T](s: String): T = decode[T](s).getOrElse(null).asInstanceOf[T]
}
这样做的目的是简单地能够使用任何对象调用 JsonConverter 并将其转换为 to/from json jsonConverter.toJson(0) must equalTo("0")
,但是当我尝试编译它时我得到以下信息:
[error] could not find implicit value for parameter encoder: io.circe.Encoder[T]
[error] override def toJson[T](t: T): String = t.asJson.noSpaces
[error] ^
[error] could not find implicit value for parameter decoder: io.circe.Decoder[T]
[error] override def fromJson[T](s: String): T = decode[T](s).getOrElse(null).asInstanceOf[T]
[error] ^
[error] two errors found
我当然可以有一个 class,我打算通过转换器放置的所有东西都继承自它,但我的印象是 circe 可以自动生成 encoders/decoders?
除非您可以实施将任何对象变成 Json... 的策略,否则您想要的是行不通的,这似乎不太可能。 Circe(和许多其他库)选择使用一种称为 Type 类 的通用模式,以便于定义您想要做某事的方式,在本例中为 Encoder
/Decoder
,因为特定类型.
如果您不熟悉 类 类型,我建议您研究它们。然后查看 Circe 文档,了解如何具体实施 Encoders/Decoders。
根据 Idan Waisman 的回答和 C4stor in my duplicate ,我使用了类型 类 模式。为简洁起见,我仅提供用于解码的示例代码 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
对象内容并创建一个特征(我制作 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]
}
接下来在大量使用 json 解码的包(例如 com.example.app.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
隐含
- 对于具有
io.circe.Decoder[T]
或可以使用 Auto
implicits 生成的任何类型 T
,您可以获得 JsonDecoder[T]
- 您不需要在每个文件中导入
io.circe.generic.auto._
- 您只需更改
com.example.app.json
包对象内容即可在 json 库之间切换。
例如,您可以切换到 json4s(尽管我做了相反的操作,从 json4s 切换到 circe)。为 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 解析器。
我正在尝试使用 scala json 库 Circe,将其包装在一个简单的特征中以提供转换 to/from json 我有以下内容:
import io.circe.generic.auto._
import io.circe.parser._
import io.circe.syntax._
trait JsonConverter {
def toJson[T](t : T) : String
def fromJson[T](s: String) : T
}
case class CirceJsonConverter() extends JsonConverter{
override def toJson[T](t: T): String = t.asJson.noSpaces
override def fromJson[T](s: String): T = decode[T](s).getOrElse(null).asInstanceOf[T]
}
这样做的目的是简单地能够使用任何对象调用 JsonConverter 并将其转换为 to/from json jsonConverter.toJson(0) must equalTo("0")
,但是当我尝试编译它时我得到以下信息:
[error] could not find implicit value for parameter encoder: io.circe.Encoder[T]
[error] override def toJson[T](t: T): String = t.asJson.noSpaces
[error] ^
[error] could not find implicit value for parameter decoder: io.circe.Decoder[T]
[error] override def fromJson[T](s: String): T = decode[T](s).getOrElse(null).asInstanceOf[T]
[error] ^
[error] two errors found
我当然可以有一个 class,我打算通过转换器放置的所有东西都继承自它,但我的印象是 circe 可以自动生成 encoders/decoders?
除非您可以实施将任何对象变成 Json... 的策略,否则您想要的是行不通的,这似乎不太可能。 Circe(和许多其他库)选择使用一种称为 Type 类 的通用模式,以便于定义您想要做某事的方式,在本例中为 Encoder
/Decoder
,因为特定类型.
如果您不熟悉 类 类型,我建议您研究它们。然后查看 Circe 文档,了解如何具体实施 Encoders/Decoders。
根据 Idan Waisman 的回答和 C4stor
首先,让我们定义将用于注入 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
对象内容并创建一个特征(我制作 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]
}
接下来在大量使用 json 解码的包(例如 com.example.app.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
中的所有源文件在范围 中都有 - 对于具有
io.circe.Decoder[T]
或可以使用Auto
implicits 生成的任何类型 - 您不需要在每个文件中导入
io.circe.generic.auto._
- 您只需更改
com.example.app.json
包对象内容即可在 json 库之间切换。
Auto
隐含
T
,您可以获得 JsonDecoder[T]
例如,您可以切换到 json4s(尽管我做了相反的操作,从 json4s 切换到 circe)。为 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 解析器。