I'm trying to decode json in refract-style with argonaut.
Scastie: http://scastie.org/15196
Error: Attempt to decode value on failed cursor.: [*.--(meta)]
I don't see why it wouldn't work, everything on meta
is optional, even Meta
itself.
Sample JSON:
{
"element": "member",
"content": {
"key": {
"element": "string",
"content": "Content-Type"
},
"value": {
"element": "string",
"content": "application/json"
}
}
}
Code so far:
/***
scalaVersion := "2.11.7"
val argonautVersion = "6.1"
val scalazVersion = "7.1.6"
libraryDependencies ++= Seq(
"io.argonaut" %% "argonaut" % argonautVersion
, "org.scalaz" %% "scalaz-core" % scalazVersion
, "com.github.alexarchambault" %% s"argonaut-shapeless_$argonautVersion" % "0.3.1"
, "org.scalatest" %% "scalatest" % "2.2.4" % "test"
)
*/
import scala.language.existentials
import scalaz._, Scalaz._
import argonaut._, Argonaut._, Shapeless._
case class Document(content: Seq[Int])
case class Meta(description: Option[String], classes: Seq[String], id: Option[String])
case class Member(meta: Option[Meta], attributes: Option[MemberAttributes], content: KeyValue)
case class MemberAttributes(typeAttributes: Seq[String], default: Seq[StringElement])
case class KeyValue(key: StringElement, value: Element[_])
sealed trait Element[T] {
def content: T
}
case class StringElement(content: String) extends Element[String]
case class ArrayElement(content: Seq[StringElement], attributes: MemberAttributes) extends Element[Seq[StringElement]]
object Parser {
def validateElement(name: String): HCursor => Boolean = { c =>
(c --\ "element").as[String].toDisjunction.fold(_ => false, _ == name)
}
def decodeAndValidate[T: DecodeJson](name: String): DecodeJson[T] =
DecodeJson.of[T].validate(validateElement(name), s"element name should be $name")
def elementDecode: DecodeJson[Element[_]] = DecodeJson(c =>
(c --\ "element").as[String].flatMap { kind =>
kind match {
case "string" => DecodeJson.of[StringElement].decode(c).map({ x => x: Element[_] })
case "array" => DecodeJson.of[ArrayElement].decode(c).map({ x => x: Element[_] })
case _ => DecodeResult.fail("expected string or array as member value", c.history)
}
}
)
def stringDecode: DecodeJson[StringElement] = decodeAndValidate[StringElement]("string")
implicit def keyvalueDecode: DecodeJson[KeyValue] = jdecode2L(KeyValue.apply)("key", "value")(stringDecode, elementDecode)
def documentDecode: DecodeJson[Document] = decodeAndValidate[Document]("parseResult")
def memberDecode: DecodeJson[Member] = decodeAndValidate[Member]("member")
}
object Decoders {
implicit def documentDecode: DecodeJson[Document] = Parser.documentDecode
implicit def memberDecode: DecodeJson[Member] = Parser.memberDecode
}
object Main extends App {
import Decoders._
val shortMember = """
{
"element": "member",
"content": {
"key": {
"element": "string",
"content": "Content-Type"
},
"value": {
"element": "string",
"content": "application/json"
}
}
}
"""
println(Parse.decodeEither[Member](shortMember))
}