1

What is wrong with the MainClassEncodeJson method below?

Have been following the example for Implicit JSON conversion with Scala http://lollyrock.com/articles/scala-implicit-conversion/

This question is similar to: Encoding nested classes using scala argonaut

The difference being an additional layer/s of nesting.

Am getting the following error from the compiler:

Cannot resolve reference EncodeJson with such signature

Thanks for in advance.

Have included the Encoder and Decoder for completeness


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)

}
1
  • I'm not quite sure on how to change it to make it work, but I think the problem is in the definition of addresses: ("addresses" := m.hat.nxt.addresses). This should be an array of address objects. Commented Mar 2, 2016 at 13:57

1 Answer 1

2

Using version 6.1 with Scalaz 7.1.x I got the following to compile using the CodecJson\[_\] and casecodecN functions.

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")

}

My build.sbt looks like this:

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,
)

By using this way of defining the encode/decode - when using simple case classes to embody JSON object literals - I think we end up with simpler code to maintain due to improved readability and reduction of moving parts (it's all declarative as opposed to following the for-comprehension logic). I also find it is a more composable definition of the problem so I can start out small without worrying about what wraps inner case classes.

You will need to put the CodecJson[_] implicits in order of need (i.e. define the inner case class codec implicits before outer ones that use them) or you will get compile-time warnings.

There is also a helpful example in the QuickStart documentation on the Argonaut website.

Sign up to request clarification or add additional context in comments.

2 Comments

implicit val mainClassCodec: CodecJson[MainClass] = casecodec3(MainClass.apply, MainClass.unapply)( "txid", "hat", "version", "bot" , "time" , "locktime") Would also be needed, right?
Yes, the code block should scroll down. It has this definition: implicit val mainClassCodec: CodecJson[MainClass] = casecodec6(MainClass.apply, MainClass.unapply)("txid", "hat", "version", "bot", "time", "locktime")

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.