【问题标题】:Circe parse json from snake case keysCirce 从蛇盒键中解析 json
【发布时间】:2019-09-15 22:28:21
【问题描述】:

我有以下案例类:

final case class Camel(firstName: String, lastName: String, waterPerDay: Int)

和circe配置:

object CirceImplicits {

  import io.circe.syntax._
  import io.circe.generic.semiauto._
  import io.circe.{Encoder, Decoder, Json}
  import io.circe.generic.extras.Configuration

  implicit val customConfig: Configuration =
    Configuration.default.withSnakeCaseMemberNames.withDefaults
  implicit lazy val camelEncoder: Encoder[Camel] = deriveEncoder
  implicit lazy val camelDecoder: Decoder[Camel] = deriveDecoder
}

没关系,当针对这个进行测试时:

val camel = Camel(firstName = "Camelbek", lastName = "Camelov", waterPerDay = 30)

private val camelJ = Json.obj(
    "firstName" -> Json.fromString("Camelbek"),
    "lastName" -> Json.fromString("Camelov"),
    "waterPerDay" -> Json.fromInt(30)
)

"Decoder" must "decode camel types" in {
    camelJ.as[Camel] shouldBe Right(camel)
}

但是这个测试没有通过:

val camel = Camel(firstName = "Camelbek", lastName = "Camelov", waterPerDay = 30)

private val camelJ = Json.obj(
    "first_name" -> Json.fromString("Camelbek"),
    "last_name" -> Json.fromString("Camelov"),
    "water_per_day" -> Json.fromInt(30)
)

"Decoder" must "decode camel types" in {
    camelJ.as[Camel] shouldBe Right(camel)
}

如何正确配置 circe 以便能够在蛇案例中使用键解析 json?

我使用的是circe版本0.10.0

【问题讨论】:

    标签: scala circe


    【解决方案1】:

    解决方案 1

    Circe 从您的案例类实例中获取字段名称并使用游标遍历 JSON,尝试获取每个字段名称的值并尝试将其转换为您想要的类型。

    这意味着您的解码器将无法处理这两种情况。

    这个问题的解决方法是写两个解码器:

    1. 基本解码器(deriveEncoder 可以使用)
    2. 使用 HCursor 浏览 JSON 并获取蛇形案例密钥的编码器
    val decoderDerived: Decoder[Camel] = deriveDecoder
    val decoderCamelSnake: Decoder[Camel] = (c: HCursor) =>
        for {
          firstName <- c.downField("first_name").as[String]
          lastName <- c.downField("last_name").as[String]
          waterPerDay <- c.downField("water_per_day").as[Int]
        } yield {
          Camel(firstName, lastName, waterPerDay)
        }
    

    然后你可以使用Decoder#or将这两个解码器合二为一

    implicit val decoder: Decode[Camel] = decoderDerived or decoderCamelSnake
    

    Decoder#or 将尝试使用第一个解码器进行解码,如果失败,则会尝试第二个。

    解决方案 2

    如果您可以只使用 camel_case 输入,那么您可以使用 "io.circe" %% "circe-generic-extras" % circeVersion 包中的 @ConfiguredJsonCodec。请注意,要使用此注解,您还需要包含天堂编译器插件。

    addCompilerPlugin(
      "org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full
    )
    
    @ConfiguredJsonCodec
    case class User(
      firstName: String,
      lastName: String
    )
    
    object User {
      implicit val customConfig: Configuration = Configuration.default.withSnakeCaseMemberNames
    }
    
    val userJson = User("John", "Doe").asJson
    println(userJson)
    // { "first_name" : "John", "last_name" : "Doe" } 
    
    val decodedUser = decode[User](userJson.toString)
    println(decodedUser)
    // Right(User("John", "Doe"))
    

    另请注意,您不需要编写自定义解码器和编码器派生程序,因为该配置会为您完成。

    【讨论】:

    • 我玩过它,发现它是可能的,我会在一秒钟内更新我的答案
    • 我也找到了相同的解决方案,但无论如何感谢您花费的时间和工作?
    【解决方案2】:

    另一种不带注释的解决方案:

    case class Camel(firstName: String, lastName: String)
    
    object Camel extends AutoDerivation {
      implicit val config: Configuration = Configuration.default.withSnakeCaseMemberNames
      implicit val decoder: Decoder[Camel] = exportDecoder[Camel].instance
      implicit val encoder: Encoder[Camel] = exportEncoder[Camel].instance
    }
    
      val json = Camel("aaa", "bbb").asJson.noSpaces
      val obj  = decode[Camel](json)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-24
      • 2021-06-09
      • 2020-02-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多