Skip to content

Instantly share code, notes, and snippets.

@sam
Created August 23, 2016 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sam/e28e7ea1d13215234fdcf6dde1991436 to your computer and use it in GitHub Desktop.
Save sam/e28e7ea1d13215234fdcf6dde1991436 to your computer and use it in GitHub Desktop.
Example of a json4s Format for a sealed trait (Id) with two implementations (NewId or IdWithRev).
import org.json4s._
case object IdSerializer extends CustomSerializer[Id](formats => ( {
case JObject(JField("prefix", JString(prefix)) :: JField("id", JString(id)) :: JField("rev", JString(rev)) :: Nil) => IdWithRev(prefix, id, rev)
case JObject(JField("prefix", JString(prefix)) :: JField("id", JString(id)) :: Nil) => NewId(prefix, id)
}, {
case NewId(prefix, id) => JObject(JField("prefix", JString(prefix)) :: JField("id", JString(id)) :: Nil)
case IdWithRev(prefix, id, rev) => JObject(JField("prefix", JString(prefix)) :: JField("id", JString(id)) :: JField("rev", JString(rev)) :: Nil)
}
))
@sam
Copy link
Author

sam commented Aug 23, 2016

This doesn't work in argonaut:

val CodecNewId = casecodec2(NewId.apply, NewId.unapply)("prefix", "id")
val CodecIdWithRev = casecodec3(IdWithRev.apply, IdWithRev.unapply)("prefix", "id", "rev")

implicit val CodecId: CodecJson[Id] =
  CodecJson({
    case NewId(prefix, id) =>
      ("prefix" := prefix) ->: ("id" := id) ->: jEmptyObject
    case IdWithRev(prefix, id, rev) =>
      ("prefix" := prefix) ->: ("id" := id) ->: ("rev" := rev) ->: jEmptyObject
  },
   CodecIdWithRev.Decoder ||| CodecNewId.Decoder
  )

@sam
Copy link
Author

sam commented Aug 23, 2016

This seems to work. It's basically just lifting the contents of the ||| operator and type-casting the fallback decoder:

val CodecNewId = casecodec2(NewId.apply, NewId.unapply)("prefix", "id")
val CodecIdWithRev = casecodec3(IdWithRev.apply, IdWithRev.unapply)("prefix", "id", "rev")

implicit val CodecId: CodecJson[Id] =
  CodecJson.derived[Id](
    EncodeJson {
      case id: NewId => CodecNewId(id)
      case id: IdWithRev => CodecIdWithRev(id)
    },
    DecodeJson[Id](c => {
      val q = CodecIdWithRev(c).map(a => a: Id)
      q.result.fold(_ => CodecNewId(c).map(a => a: Id), _ => q)
    })
  )

There's got to be a prettier way to do this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment