Skip to content

Instantly share code, notes, and snippets.

@mbbx6spp
Created March 2, 2016 14:15
Show Gist options
  • Save mbbx6spp/df771b3aaaea90d20dd0 to your computer and use it in GitHub Desktop.
Save mbbx6spp/df771b3aaaea90d20dd0 to your computer and use it in GitHub Desktop.

StackOverflow Answer

Answer in Gist form to avoid SO code block rendering issues which scrolls unintuitively.

Question reference: http://stackoverflow.com/questions/35747753/complex-encoding-of-multiple-nested-classes-using-scala-argonaut

Answer: http://stackoverflow.com/a/35749093/705041

Answer

Using version 6.1 with Scalaz 7.1.x I got the following to compile using the link:http://argonaut.io/doc/codec/[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 link:http://argonaut.io/doc/quickstart/[QuickStart] documentation on the Argonaut website.

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")
}
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,
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment