【问题标题】:Complex Encoding of multiple nested classes using scala argonaut使用 scala argonaut 对多个嵌套类进行复杂编码
【发布时间】:2016-03-02 12:51:23
【问题描述】:

下面的MainClassEncodeJson方法有什么问题?

一直在关注使用 Scala http://lollyrock.com/articles/scala-implicit-conversion/ 进行隐式 JSON 转换的示例

这个问题类似于:Encoding nested classes using scala argonaut

不同之处在于额外的嵌套层。

我从编译器收到以下错误:

Cannot resolve reference EncodeJson with such signature

提前感谢您。

为了完整性,已经包含了编码器和解码器


object ImplicitConversion {

  case class MainClass (txid: String,hat: Hat,version: Int,bot: Bot, time: Int, locktime: Int)
  case class Hat (value: Float,n: Int,nxt: Nxt)
  case class Nxt (typetx: String,reqsigs: Int,addresses: List[Address])
  case class Bot (base: String,sequence: Int)
  case class Address (address: String)


  // implicit conversion with argonaut
  implicit def MainClassEncodeJson: EncodeJson[MainClass] =
    EncodeJson((m: MainClass) =>
      ("txid" := m.txid) ->:
      ("hat" := Json (
          ("value" := m.hat.value),
          ("n" := m.hat.n),
          ("nxt" := Json (
            ("typetx" := m.hat.nxt.typetx),
            ("reqsigs" := m.hat.nxt.reqsigs),
            ("addresses" := m.hat.nxt.addresses)
          )
            )  ->: jEmptyObject
        )
          ) ->: jEmptyObject
      ("version" := m.version) ->:
      ("bot" := Json (
              ("base" := m.bot.base)
              ("sequence" := m.bot.sequence)
        )
          ) ->: jEmptyObject
        ("time" := m.time) ->: 
        ("locktime" := m.locktime) ->:
    )

  implicit def MainClassDecodeJson: DecodeJson[MainClass] =
    DecodeJson(c => for {
      txid <- (c --\ "txid").as[String]
      hat <- (c --\ "hat").as[Json]
      version <- (c --\ "version").as[Int]
      bot <- (c --\ "bot").as[Json]
      time <- (c --\ "time").as[Int]
      locktime <- (c --\ "locktime").as[Int]

      // extract data from hat
      value <- (hat.acursor --\ "value").as[Float]
      n <- (hat.acursor --\ "n").as[Int]
      nxt <- (hat.acursor --\ "nxt").as[Json]

      // extract data from nxt
      typetx <- (nxt.acursor --\ "typetx").as[String]
      reqsigs <- (nxt.acursor --\ "reqsigs").as[Int]
      addresses <- (nxt.acursor --\ "addresses").as[List[Address]]

      // extract data from bot
      base <- (bot.acursor --\ "base").as[String]
      sequence <- (bot.acursor --\ "sequence").as[Int]

    } yield MainClass(txid, hat(value, n, Nxt(typetx, reqsigs, addresses)), 
                     version, Bot(base, sequence), time, locktime)

}

【问题讨论】:

  • 我不太确定如何更改它以使其工作,但我认为问题在于地址的定义:("addresses" := m.hat.nxt.addresses)。这应该是一个地址对象数组。

标签: json scala encoding argonaut


【解决方案1】:

将 6.1 版与 Scalaz 7.1.x 一起使用,我使用 CodecJson\[_\]casecodecN 函数编译了以下内容。

import scalaz._, Scalaz._
import argonaut._, Argonaut._

object ImplicitConversion {

  case class MainClass( txid: String
                      , hat: Hat
                      , version: Int
                      , bot: Bot
                      , time: Int
                      , locktime: Int)

  case class Hat( value: Float
                , n: Int
                , nxt: Nxt)

  case class Nxt( typetx: String
                , reqsigs: Int
                , addresses: List[Address])

  case class Bot( base: String
                , sequence: Int)

  case class Address(address: String)


  implicit val botCodec: CodecJson[Bot] =
    casecodec2(Bot.apply, Bot.unapply)("base", "sequence")

  implicit val addressCodec: CodecJson[Address] =
    casecodec1(Address.apply, Address.unapply)("address")

  implicit val nxtCodec: CodecJson[Nxt] =
    casecodec3(Nxt.apply, Nxt.unapply)("typetx", "reqsigs", "addresses")

  implicit val hatCodec: CodecJson[Hat] =
    casecodec3(Hat.apply, Hat.unapply)("value", "n", "nxt")

  implicit val mainClassCodec: CodecJson[MainClass] =
    casecodec6(MainClass.apply, MainClass.unapply)("txid", "hat", "version", "bot", "time", "locktime")

}

我的build.sbt 看起来像这样:

name := "stackoverflow"

scalaVersion := "2.11.7"

val scalazVersion = "7.1.0"

val argonautVersion = "6.1"

libraryDependencies ++= Seq(
  "org.scalaz"      %% "scalaz-core"    % scalazVersion,
  "io.argonaut"     %% "argonaut"       % argonautVersion,
)

通过使用这种定义编码/解码的方式 - 当使用简单的案例类来体现 JSON 对象字面量时 - 我认为由于提高了可读性和减少了移动部件(这都是声明性的,而不是相反的),我认为我们最终会得到更简单的代码来维护遵循理解逻辑)。我还发现它是对问题的更可组合的定义,因此我可以从小处着手,而不必担心内部案例类的包装。

您需要将CodecJson[_] 隐式按需要的顺序放置(即在使用它们的外部类编解码器之前定义内部案例类编解码器隐式),否则您将收到编译时警告。

Argonaut 网站上的 QuickStart 文档中也有一个有用的示例。

【讨论】:

  • implicit val mainClassCodec: CodecJson[MainClass] = casecodec3(MainClass.apply, MainClass.unapply)( "txid", "hat", "version", "bot" , "time" , "locktime ") 也需要,对吧?
  • 是的,代码块应该向下滚动。它有这样的定义:implicit val mainClassCodec: CodecJson[MainClass] = casecodec6(MainClass.apply, MainClass.unapply)("txid", "hat", "version", "bot", "time", "locktime")
猜你喜欢
  • 1970-01-01
  • 2021-07-16
  • 2014-11-01
  • 1970-01-01
  • 2018-09-27
  • 1970-01-01
  • 1970-01-01
  • 2019-07-02
  • 1970-01-01
相关资源
最近更新 更多