首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >仿制Scala Circe

仿制Scala Circe
EN

Stack Overflow用户
提问于 2016-09-22 20:40:37
回答 2查看 4.4K关注 0票数 5

我正在尝试使用scala库Circe,将它包装为一个简单的特性,以提供到或从json的转换,我有以下内容:

代码语言:javascript
复制
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,并让它将其转换为或从json转换为json,但是,当我试图编译它时,我会得到以下内容:

代码语言:javascript
复制
[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

当然,我可以有一个类,我想通过转换器继承所有的东西,但是我有这样的印象: circe可以自动生成编码器/解码器?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-09-22 21:12:07

你想要的是不会起作用的,除非你能实现一个把任何物体变成Json的策略.这似乎不太可能。Circe (和许多其他库)选择使用一个名为type类的通用模式,以便为特定类型定义您想要做的事情(在本例中是Encoder/Decoder )。

如果您不熟悉类型类,我建议您研究它们。然后看看Circe文档,看看如何具体地实现编码器/解码器。

票数 4
EN

Stack Overflow用户

发布于 2016-12-12 13:39:34

依循Idan和C4stor 回答在复制的问题中,我使用了Type模式。为了简洁起见,我只提供了用于解码json的示例代码。编码可以用完全相同的方式实现。

首先,让我们定义用于注入json解码器依赖项的特性:

代码语言:javascript
复制
trait JsonDecoder[T] {
  def apply(s: String): Option[T]
}

接下来,我们定义创建实现此特性的实例的对象:

代码语言:javascript
复制
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对象内容并创建一个特性(我使按下使此特性可用为io.circe.generic.Auto):

代码语言:javascript
复制
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特性,并为给定类型的T提供隐式返回JsonDecoder[T]

代码语言:javascript
复制
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
  • 您可以为具有JsonDecoder[T]的任何类型的T获取io.circe.Decoder[T],也可以为其生成具有io.circe.Decoder[T]io.circe.Decoder[T]
  • 您不需要在每个文件中导入io.circe.generic.auto._
  • 只需更改com.example.app.json包对象内容,就可以在json库之间切换。

例如,您可以切换到json4s (尽管我做了相反的操作,并从json4s切换到circe )。实现JsonDecoder[T]的提供程序

代码语言:javascript
复制
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包对象内容更改为:

代码语言:javascript
复制
package com.example.app

import org.json4s.DefaultFormats

package object json {
    implicit def decoder[T: Manifest]: JsonDecoder[T] = Json4SDecoderProvider(DefaultFormats)[T]
}

使用Type Classes模式,您可以得到编译时依赖注入。与运行时依赖注入相比,这提供了更少的灵活性,但我怀疑您是否需要在运行时切换json解析器。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39648511

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档