The use case Im trying to get working with using Circle is as follows. Given a stream of JSON messages I want to match on the op and convert the message from and to the appropriate type. The code below shows all the details. However the code des not compile since it need implicit encoders for the different ResponseMessag:es.
Why is it not enogh to use
import io.circe.generic.auto._
to get encoders and decoders for the differentResponseMessage
types and then only write a custom forResponseMessage
? How can I change the example below to get the tests to pass? Is there a way to not have to decode the different values of ResponseOpType as Strings, I would like atrait
hierarchy but it gets decoded in the wrong format (as a JSON object not just a plain string)??
object OpTypes {
type ResponseOpType = String
val Connection: ResponseOpType = "connection"
val Status: ResponseOpType = "status"
}
import OpTypes._
sealed trait ResponseMessage {
/* The operation type */
def op: ResponseOpType
/* Client generated unique id to link request with response (like json rpc) */
def id: Integer
}
case class ConnectionMessage (
op: ResponseOpType,
id: Integer,
/* The connection id */
connectionId: String
) extends ResponseMessage
case class StatusMessage (
op: ResponseOpType,
id: Integer,
/* Additional message in case of a failure */
errorMessage: String,
/* The type of error in case of a failure */
errorCode: String,
/* The connection id */
connectionId: String,
/* Is the connection now closed */
connectionClosed: Boolean,
/* The status of the last request */
statusCode: String
) extends ResponseMessage
case class UnableToParseStreamResponseMessage (op:String="Error", id:Integer = 0) extends ResponseMessage
test("Circle support") {
import io.circe.{Decoder, Encoder}
import io.circe.generic.auto._
import io.circe.syntax._
import io.circe.parser.decode
implicit val decodeResponseMessage: Decoder[ResponseMessage] = Decoder.instance(c => {
c.get[OpTypes.ResponseOpType]("op").flatMap {
case OpTypes.Connection => c.as[ConnectionMessage]
case OpTypes.Status => c.as[StatusMessage]
case _ => c.as[UnableToParseStreamResponseMessage]
}
})
implicit val encodeResponseMessage: Encoder[ResponseMessage] = new Encoder[ResponseMessage] {
final def apply(a: ResponseMessage): Json = Json.obj(
//Im encoding ResponseMessage wich only have a subset of all the parameters I need???
)
}
val originalJson =
"""
|{"op":"connection",
| "id":1,
| "connectionId":"1"
| }
""".stripMargin
val original = ConnectionMessage(op ="connection", id = 1, connectionId = "1")
decode[ResponseMessage](originalJson) shouldBe original
originalJson shouldBe original.asJson.noSpaces
}