【问题标题】:json Generic decoder with default values using scala with circe带有默认值的json通用解码器,使用带有circe的scala
【发布时间】:2020-06-05 03:12:33
【问题描述】:

我遇到了一个奇怪的情况。
我正在尝试构建一个采用类型和 JSON 的方法 并将其构建到案例类实例中,并在需要时自动完成缺失的键值。
到目前为止,我设法单独做所有事情,但不是全部。
具有默认值的案例类:

case class Foo(a: String = "empty String", b: Option[Int] = Some(1))

当我进行转换时:

import io.circe.generic.extras.auto._
import io.circe.generic.extras.Configuration
import io.circe.parser.decode
implicit val customConfig: Configuration = Configuration.default.withDefaults

println(decode[Foo]("{}"))

这是我得到的输出:

Right(Foo(empty String,Some(1)))

这正如我预期的那样工作

但是当我把它放到一个通用方法中时,由于错误,它需要一个选项:

Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: DecodingFailure(Attempt to decode value on failed cursor, List(DownField(a)))

所以我将案例类更改为

case class Foo(a: Option[String] = Some("empty String"), b: Option[Int] = Some(1))

并添加解码器:

object Foo{
    implicit val decoder:Decoder[Foo] = deriveDecoder[Foo]
}

到方法:

import io.circe.Decoder
import io.circe.parser.decode

def convertToObj[T](jsonStr: String)(implicit decoder: Decoder[T]): T = { 
    decode[T](jsonStr)
    match {
      case Right(value) => value
      case Left(error) =>  throw error
    }
}
println(convertToObj[Foo]("{}"))

输出是:

Foo(None,None)

所以现在我丢失了我设置的默认值,也无法使用自动解码器。

如何将我的两个愿望合并为一种方法?

【问题讨论】:

  • 你是什么意思:“但是当我把它放到一个泛型方法中时,由于错误,它需要一个选项:”?什么通用方法?我是否理解您正在更改您的课程,因为您在“将其放入通用方法”后遇到错误?
  • 你理解的没错,我为了让它工作而改变了类,方法是convertToObj[Foo]("{}")

标签: json scala generics circe


【解决方案1】:

您需要执行以下操作:

package foo.bar

import io.circe.Decoder
import io.circe.generic.extras.semiauto
import io.circe.generic.extras.Configuration
import io.circe.parser.decode

case class Foo(a: String = "empty String", b: Option[Int] = Some(1))

object Foo {
  implicit val customConfig: Configuration = Configuration.default.withDefaults
  implicit val decoder: Decoder[Foo]       = semiauto.deriveConfiguredDecoder[Foo]
}

object TestApp extends App {
  def convertToObj[T](jsonStr: String)(implicit decoder: Decoder[T]): T =
    decode[T](jsonStr) match {
      case Right(value) => value
      case Left(error)  => throw error
    }

  println(convertToObj[Foo]("{}"))
}

但是,您可以让 circe 自动为您派生解码器,这样您就可以使用更少的样板代码:

package foo.bar

import io.circe.Decoder
import io.circe.generic.extras.auto._
import io.circe.generic.extras.Configuration
import io.circe.parser.decode

case class Foo(a: String = "empty String", b: Option[Int] = Some(1))

object TestApp extends App {

  implicit val customConfig: Configuration = Configuration.default.withDefaults

  def convertToObj[T](jsonStr: String)(implicit decoder: Decoder[T]): T =
    decode[T](jsonStr) match {
      case Right(value) => value
      case Left(error)  => throw error
    }

  println(convertToObj[Foo]("{}"))
}

这两个例子都给了我输出:Foo(empty String,Some(1))

注意:

method deriveDecoder in object semiauto is deprecated (since 0.12.0): Use deriveConfiguredDecoder

【讨论】:

  • 感谢您的回答和注意。第一个示例完美运行,但是第二个示例在编译时产生错误“找不到参数解码器的隐含值:io.circe.Decoder[Foo]”
  • 奇怪,它对我有用。你能仔细检查一下进口吗?特别是io.circe.generic.extras.auto._我测试的circe版本是:0.12.2
  • 我仔细检查了所有内容..但是我的 circe 版本是 0.13.0
猜你喜欢
  • 2020-07-20
  • 2018-10-22
  • 2016-06-23
  • 2020-05-31
  • 2020-04-14
  • 1970-01-01
  • 2017-04-24
  • 2017-07-10
  • 2017-10-03
相关资源
最近更新 更多