【问题标题】:ObjectMapper to serialize a class with Enumeration memberObjectMapper 用枚举成员序列化一个类
【发布时间】:2020-09-04 18:59:57
【问题描述】:

我在 Scala 中有一个枚举

object Status extends Enumeration {
  type Status = Value
  val Success = Value
  val Error = Value
}

这是在下面使用 -

case class Response(
    status: Status,
    errorMessage: String
)

我想将Response 存储在一个文件中。所以,我正在使用 Jackson 对象映射器 (com.fasterxml.jackson.databind.ObjectMapper ) 对其进行序列化。

writeOutputToFile(filePath: Path , objectMapper.writeValueAsString(response)) 

但是,对象映射器将空 json 写入文件。我知道对象映射器需要一个 getter 方法来序列化。这就是失败的原因吗?我需要自定义对象映射器吗?

【问题讨论】:

  • stackoverflow.com/questions/28270621/… 回答你的问题了吗?
  • 只是其中的一部分。我主要关心的是枚举类。 ObjectMapper 将其打印为{"status":{"scala$Enumeration$Val$$i":0},"message":null}
  • Jackson 是 Java 库,它不了解 Scala 是如何定义事物的。这就是为什么 wrapper 可能会有所帮助。虽然简单的方法是包装器并且没有-Enumeration
  • 您可能更喜欢带有案例对象的密封特征

标签: scala jackson objectmapper


【解决方案1】:

您可以为所有枚举定义通用序列化器和反序列化器,然后为每个枚举注册相应的实例对:

class EnumSerializer[T <: scala.Enumeration](e: T) extends JsonSerializer[T#Value] {
  override def serialize(x: T#Value, jg: JsonGenerator, spro: SerializerProvider): Unit = 
    jg.writeString(x.toString)
}

class EnumDeserializer[T <: scala.Enumeration](e: T) extends JsonDeserializer[T#Value] {
  private[this] val ec = new ConcurrentHashMap[String, T#Value]

  override def deserialize(jp: JsonParser, ctxt: DeserializationContext): T#Value = Try {
    val s = jp.getValueAsString
    var x = ec.get(s)
    if (x eq null) {
      x = e.values.iterator.find(_.toString == s).get
      ec.put(s, x)
    }
    x
  }.getOrElse(ctxt.handleUnexpectedToken(classOf[T#Value], jp).asInstanceOf[T#Value])
}

val objectMapper: ObjectMapper with ScalaObjectMapper = {
  val jsonFactory = new JsonFactoryBuilder()
    .configure(...)
    .build()
  new ObjectMapper(jsonFactory) with ScalaObjectMapper {
    registerModule(DefaultScalaModule)
    registerModule(new SimpleModule()
      .addSerializer(classOf[Status], new EnumSerializer(Status))
      .addDeserializer(classOf[Status] new EnumDeserializer(Status))
      ...
    )
  }
}

建议的解决方案在运行时比在每次反序列化中仅使用Status.withName(s) 更加安全和高效。

它甚至适用于枚举值的动态定义,例如:

object Status extends Enumeration {
  type Status = Value
  val Success = Value
  val Error = Value

  def extra(name: String): Status = Value(nextId, name)
}

Status.extra("Unknown")

完整来源是here

【讨论】:

    猜你喜欢
    • 2023-03-10
    • 2014-08-20
    • 2019-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多