0

I'd like to define a class class for JSON serialisation like so:

case class Foo(id: String, variety: Variety)

sealed trait Variety
case object Bar extends Variety { override def toString = "1" }
case object Baz extends Variety { override def toString = "2" }

It should serialise and deserialise like this:

write[Foo](Foo("foo1", Bar))
"""{"id":"foo1", "variety":"1"}"""

read[Foo]("""{"id":"foo2", "variety":"2"}""")
Foo("foo2", Baz)

But it serialises to {"id":"foo2", "variety":{}} and fails to deserialise. Is it possible to use case objects like this? I'm using lift-json_2.10 2.6-M2?

Is there a better way to handle enumerations with lift-json?

Josh Glover
  • 25,142
  • 27
  • 92
  • 129

2 Answers2

1

instead of a case object, make Variety a case class and Bar/Baz vals

fommil
  • 5,757
  • 8
  • 41
  • 81
1

I am using the following classes to create a custom serializer for case objects. Just chose fieldKey and identifierOverride to suit your case if you are concerned about the format of the json.

object SpecialObjectSerializers {
  val FieldKeyDefault = "scalaObject"

  class SingleObjectSerializer[T <: AnyRef](obj: T, FieldKey : String = FieldKeyDefault,
                                             identifierOverride : Option[JValue] = None) extends Serializer[T] {
    val Identifier = identifierOverride.getOrElse(JString(obj.getClass.getName))
    override def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
      case `obj` =>
        JObject(List(JField(FieldKey, Identifier)))
    }
    override def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), T] = {
      case (_, JObject(List(JField(FieldKey, Identifier)))) => obj
    }
  }

  class RichSerializer[T](serializer: Serializer[T]) {
    def +(that: Serializer[T]) = {
      new Serializer[T] {
        override def deserialize(implicit format: Formats) = serializer.deserialize.orElse(that.deserialize)
        override def serialize(implicit format: Formats) = serializer.serialize.orElse(that.serialize)
      }
    }
  }

  implicit def toRichSerializer[T](serializer: Serializer[T]) = new RichSerializer(serializer)

  def caseObjectsSerializer[T <: AnyRef](objs: T*): Serializer[T] = {
    val serializers: Seq[Serializer[T]] = objs.map(new SingleObjectSerializer(_))
    serializers.reduceLeft[Serializer[T]] {
      case (s1, s2) => s1 + s2
    }
  }
}