无法使用JSON4S序列化枚举

时间:2016-08-09 17:14:21

标签: json scala serialization enums json4s

我有一个像这样的枚举类层次结构:

abstract class EnumBase {
  def code: String
}

abstract class EnumObject[EnumT <: EnumBase] {...}

我在很多地方使用它。这是一个例子:

sealed abstract case class StateCode(code: String) extends EnumBase

object StateCode extends EnumObject[StateCode] {...}

我想将包含StateCode深入嵌套的案例类序列化为JSON。我编写了以下自定义序列化程序来执行此操作:

class EnumSerializer[EnumT <: EnumBase: scala.reflect.ClassTag](enumObject: EnumObject[EnumT])
  extends org.json4s.Serializer[EnumT] {

  val EnumerationClass = scala.reflect.classTag[EnumT].runtimeClass

  def deserialize(implicit format: Formats):
  PartialFunction[(TypeInfo, JValue), EnumT] = {
    case (TypeInfo(EnumerationClass, _), json) => json match {
      ...
    }
  }

  def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
    case i: EnumT => JString(i.code)
    case _ => JString("BLAH")
  }
}

当我序列化像这样的案例类时,结果是JSON只是"stateCode":{}

MyClass(id = 123,
        version = 1,
        year = 2016,
        input = MyInput(
          ...
          stateCode = StateCode.CO
        )
 )

注意我在Extraction.decompose的自定义反序列化器中的MyInput实例上使用了MyClass,希望我的自定义序列化程序可以在那里启动。

我还尝试编写一个专门用于StateCode的自定义序列化程序,只是为了看看我的通用尝试是否是问题。那也没有帮助。

关于如何让JSON4S序列化我的枚举的任何想法?

2 个答案:

答案 0 :(得分:0)

你可以试试这个:

abstract class EnumBase {
  def code: String
}

abstract class EnumObject[EnumT <: EnumBase] {}

final case class StateCode(code: String) extends EnumBase

object StateCode extends EnumObject[StateCode] {
  val CO = new StateCode("CO")
  val CA = new StateCode("CA")
}

case class ClassWithStateCode(id: Int, x: StateCode)

case class MyClass(id: Int, version: Int, year: Int, co: StateCode)

这不需要定义任何序列化程序,但这可能不是您要找的。

我认为你正在做的潜在问题:

object StateCode extends EnumObject[StateCode] {
  val CO = new StateCode("CO") {}
  val CA = new StateCode("CA") {}
}

是你正在创建一个匿名类,它是StateCode的子类型case class,你应该非常小心地扩展case类,因为它们可能有错误的equals / hashcode。

答案 1 :(得分:0)

这适用于非通用版本的序列化程序,但我担心这可能无法使其成为通用

abstract class EnumBase {
  def code: String
}

abstract class EnumObject[EnumT <: EnumBase] {}

sealed abstract case class StateCode(code: String) extends EnumBase

object StateCode extends EnumObject[StateCode] {
  val CO = new StateCode("CO") {}
  val CA = new StateCode("CA") {}
}

case class ClassWithStateCode(id: Int, x: StateCode)

case class MyClass(id: Int, version: Int, year: Int, co: StateCode)

object StateCodeSerializer extends org.json4s.Serializer[StateCode] {

      override def deserialize(implicit format: Formats):
      PartialFunction[(TypeInfo, JValue), StateCode] = {
        case (TypeInfo(EnumerationClass, _), jsonx) => jsonx match {
          case i: JString => new StateCode(i.values) {}
        }
      }

      override def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
        case i: StateCode => JString(i.code)
      }
    }

    implicit val formats2 = DefaultFormats + StateCodeSerializer

    val testClass = MyClass(2, 0, 1966, StateCode.CO)
    println(write(testClass))
    println(read[MyClass](write(testClass)))