Skip to content

Commit

Permalink
Implement Json4s CustomKeySerializer (#127)
Browse files Browse the repository at this point in the history
  • Loading branch information
morgen-peschke authored and lloydmeta committed Mar 16, 2017
1 parent 91426ac commit f1e9c5d
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 2 deletions.
41 changes: 40 additions & 1 deletion enumeratum-json4s/src/main/scala/enumeratum/Json4s.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package enumeratum

import org.json4s.CustomSerializer
import org.json4s.{CustomSerializer, CustomKeySerializer}
import org.json4s.JsonAST.JString

@SuppressWarnings(Array("org.wartremover.warts.Any"))
Expand Down Expand Up @@ -44,4 +44,43 @@ object Json4s {
}
))

/**
* Returns a Json [[CustomKeySerializer]] for the given Enumeratum enum
*
* {{{
* scala> import enumeratum._
* scala> import org.json4s._
* scala> import org.json4s.native.Serialization
*
* scala> sealed trait ShirtSize extends EnumEntry
* scala> case object ShirtSize extends Enum[ShirtSize] {
* | case object Small extends ShirtSize
* | case object Medium extends ShirtSize
* | case object Large extends ShirtSize
* | val values = findValues
* | }
*
* scala> implicit val formats = Serialization.formats(NoTypeHints) + Json4s.keySerializer(ShirtSize)
*
* scala> val valueMap = ShirtSize.values.zipWithIndex.toMap
*
* scala> Serialization.write(valueMap)
* res0: String = {"Small":0,"Medium":1,"Large":2}
*
* scala> Serialization.read[Map[ShirtSize,Int]]("""{"Small":0,"Medium":1,"Large":2}""") == valueMap
* res1: Boolean = true
* }}}
*
* @param enum the enum you want to generate a Json4s key serialiser for
*/
def keySerializer[A <: EnumEntry: Manifest](enum: Enum[A]): CustomKeySerializer[A] =
new CustomKeySerializer[A](
_ =>
(
{
case s: String if enum.withNameOption(s).isDefined => enum.withName(s)
}, {
case x: A => x.entryName
}
))
}
18 changes: 17 additions & 1 deletion enumeratum-json4s/src/test/scala/enumeratum/Json4sSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import org.scalatest.{FunSpec, Matchers}

class Json4sSpec extends FunSpec with Matchers {

implicit val formats = DefaultFormats + Json4s.serializer(TrafficLight)
implicit val formats = DefaultFormats + Json4s.serializer(TrafficLight) + Json4s.keySerializer(
TrafficLight)

case class Data(tr: TrafficLight)
case class DataOpt(tr: Option[TrafficLight])
case class DataMap(tr: Map[TrafficLight, Int])

describe("to JSON") {
it("should serialize plain value to entryName") {
Expand All @@ -27,6 +29,13 @@ class Json4sSpec extends FunSpec with Matchers {
it("should serialize None to nothing") {
Serialization.write(DataOpt(tr = None)) shouldBe """{}"""
}

it("should serialize value to key") {
TrafficLight.values.foreach { value =>
val name = value.entryName
Serialization.write(DataMap(tr = Map(value -> 0))) shouldBe s"""{"tr":{"$name":0}}"""
}
}
}

describe("from JSON") {
Expand All @@ -47,6 +56,13 @@ class Json4sSpec extends FunSpec with Matchers {
Serialization.read[DataOpt]("""{}""").tr shouldBe None
}

it("should parse enum members into keys") {
TrafficLight.values.foreach { value =>
val name = value.entryName
Serialization.read[DataMap](s"""{"tr":{"$name":0}}""").tr shouldBe Map(value -> 0)
}
}

it("should parse invalid value into None") {
Serialization.read[DataOpt]("""{"tr":"bogus"}""").tr shouldBe None
Serialization.read[DataOpt]("""{"tr":17}""").tr shouldBe None
Expand Down

0 comments on commit f1e9c5d

Please sign in to comment.