在Circe中扩展自动推导不起作用

时间:2019-07-10 00:08:26

标签: json scala circe

我的问题与mixel在此处提供的第二种解决方案有关:Scala Circe with generics

请注意,在Circe的当前版本中,名为Circe的特征已重命名为AutoDerivation。

我正在使用mixel在他的StackOverflow解决方案中提供的解决方案,但无法使其正常工作。我已经尝试过将Circe版本更新为最新版本,并确保已导入Macro Paradise插件,但仍然没有运气。

这是我的代码。第一个是它自己的文件,称为CirceGeneric。

import io.circe._
import io.circe.parser._
import io.circe.generic.extras._

object CirceGeneric {
  trait JsonEncoder[T] {
    def apply(in: T): Json
  }

  trait JsonDecoder[T] {
    def apply(s: String): Either[Error, T]
  }

  object CirceEncoderProvider {
    def apply[T: Encoder]: JsonEncoder[T] = new JsonEncoder[T] {
      def apply(in: T) = Encoder[T].apply(in)
    }
  }

  object CirceDecoderProvider {
    def apply[T: Decoder]: JsonDecoder[T] = new JsonDecoder[T] {
      def apply(s: String) = decode[T](s)
    }
  }
}

object Generic extends AutoDerivation {
  import CirceGeneric._

  implicit def encoder[T: Encoder]: JsonEncoder[T] = CirceEncoderProvider[T]
  implicit def decoder[T: Decoder]: JsonDecoder[T] = CirceDecoderProvider[T]

}

第二个是使用Akka函数responseAs的单元测试方法。该方法出现在名为BaseServiceTest的类中。

  def responseTo[T]: T = {
    def response(s: String)(implicit d: JsonDecoder[T]) = {
      d.apply(responseAs[String]) match {
        case Right(value) => value
        case Left(error) => throw new IllegalArgumentException(error.fillInStackTrace)
      }
    }
    response(responseAs[String])
  }

这个想法是将responseAs [String]的结果(返回一个字符串)转换为解码的case类。

该代码的行为不符合预期。 Intellij不会检测到任何缺少的隐式内容,但是当编译时间到来时,我遇到了问题。我应该提到BaseServiceTest文件包含CirceGeneric._和Generic._的导入,因此缺少导入语句不是问题。

[错误] [...] / BaseServiceTest.scala:59:找不到参数d的隐式值:[...] CirceGeneric.JsonDecoder [T] [错误]响应(responseAs [String])

或者没有发生从Decoder [T]到JsonDecoder [T]的隐式转换,或者没有创建Decoder [T]实例。无论哪种方式,都出了问题。

1 个答案:

答案 0 :(得分:1)

您仍然需要绑定到Decoder的{​​{1}}或JsonDecoder上下文。

responseTo

这是因为您的所有代码以及链接的答案中的mixel的代码实际上都是关于从def responseTo[T : Decoder]: T = ... Decoder特质的抽象,可用于跨库支持。但是,如果没有基础JsonDecoder实例,您仍然无法构建一个实例。

现在,有一些方法可以自动为Decoder中包含的案例类生成Decoder,但是现在在您的代码中

circe.generics.auto

您要让编译器能够为任意类型提供隐式def responseTo[T]: T = { def response(s: String)(implicit d: JsonDecoder[T]) = ... ... } (即,在您的设置中,JsonDecoder)实例。正如链接问题的公认答案所解释的那样,这是不可能的。

您需要将隐式解析延迟到知道您要处理的类型的程度,尤其是可以为其提供Decoder实例。

编辑:在您对不能创建所有类型的Decoder[T]的问题的评论中的答复...

我对链接问题的理解是,他们正试图抽象出JsonDecoder库,以便允许换出JSON库实现。这样做如下:

  • 添加circe类型的类

  • 有一个包JsonDecoder,其中包含隐式内容(使用Circe),用于通过扩展json

  • 的包对象自动构造它们
  • 具有外部代码,仅引用AutoDerivation并将隐式内容导入JsonDecoder包中

然后,所有的JSON序列化和隐式解析都可以实现,而无需调用代码引用json,并且很容易将io.circe / json切换到另一个JSON库,如果想要的。但是您仍然必须使用JsonDecoder上下文绑定,并且只能使用可构造此类隐式的类型。并不是每种类型。