I am looking for a good way to decode a set of case classes from json without having to know the actual type of the message e.g. different commands coming down a websocket. Mark was kind enough to answer my question on issue #64 with an example. Trying to extend it though I am running into issues. I am a scala n00b trying to escape from java land so my apologies if its obvious to everyone else.
The problem is that if I uncomment the two lines to configure the codexes for RoomSize the compiler barfs:
package argonaut.example
import argonaut._, Argonaut._
import org.specs2.{ScalaCheck, Specification}
abstract class Message
case class RoomSize(size: Int, mType: String = "RoomSize") extends Message
case class CardDrawn(player: Long, card: Int, mType: String = "CardDrawn") extends Message
case class CardSet(cards: List[CardDrawn], mType: String = "CardSet") extends Message
class CardSetExampleMain extends Specification with ScalaCheck {
implicit lazy val CodecRoomSize: CodecJson[RoomSize] = casecodec2(RoomSize.apply, RoomSize.unapply)("size","mType")
implicit lazy val CodecCardSet: CodecJson[CardSet] = casecodec2(CardSet.apply, CardSet.unapply)("cards","mType")
implicit lazy val CodecCardDrawn: CodecJson[CardDrawn] = casecodec3(CardDrawn.apply, CardDrawn.unapply)("player", "card", "mType")
implicit lazy val CodecMessage: CodecJson[Message] = CodecJson(m => m match {
//case c @ RoomSize(_,_) => Json { "RoomSize" -> c.asJson }
case c @ CardSet(_,_) => Json { "CardSet" -> c.asJson }
case c @ CardDrawn(_,_,_) => Json { "CardDrawn" -> c.asJson}
} , c =>
//(c --\ "RoomSize").as[RoomSize].map(identity) |||
(c --\ "CardSet").as[CardSet].map(identity) |||
(c --\ "CardDrawn").as[CardDrawn].map(identity)
)
val setMessage: Message = CardSet(List(CardDrawn(1L,2),CardDrawn(3L,4)))
val drawnMessage: Message = CardDrawn(1L,2)
def is = "JsonExample" ^
"setMessage " ! {
} ^
"drawnMessage " ! {
}
def main(args: Array[String]): Unit = {
val value = CardSet(List(CardDrawn(1L,2),CardDrawn(3L,4)))
println(s"Got some good json ${value.asJson}")
val jstring =
"""{
| "cards":[
| {"player":"1","card":2,"mType":"CardDrawn"},
| {"player":"3","card":4,"mType":"CardDrawn"}
| ],
| "mType":"CardSet"
| }""".stripMargin
val parsed: Option[CardSet] =
jstring.decodeOption[CardSet]
println(s"Got a good object ${parsed.get}")
}
}
type mismatch;
found : argonaut.DecodeResult[com.github.simbo1905.scrumpoker.CardDrawn]
required: argonaut.DecodeResult[Product with Serializable with com.github.simbo1905.scrumpoker.Message]
Note: com.github.simbo1905.scrumpoker.CardDrawn <: Product with Serializable with com.github.simbo1905.scrumpoker.Message, but class DecodeResult is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)
(c --\ "CardDrawn").as[CardDrawn].map(identity) |||
^