【问题标题】:How to use Jackson to serialize Scala value classes as strings?如何使用 Jackson 将 Scala 值类序列化为字符串?
【发布时间】:2017-10-09 10:55:39
【问题描述】:

我想使用 Scala 的值类(或普通案例类)为我的程序中的某些字符串提供更强的类型。当我使用 Jackson 序列化这些类的实例时,我希望它们是字符串。

例如:

case class Brand(name: String) extends AnyVal
val brands = Seq(Brand("Coke"), Brand("Disney"))
val brandCount = Map(Brand("Coke") -> 5, Brand("Disney") -> 10)

由于Brand 只是一个字符串的包装器,我希望这些变量对应的 JSON 序列化为:

brands:     ["Coke", "Disney"]
brandCount: {"Coke": 5, "Disney": 10}

默认情况下我得到:

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule

val mapper = new ObjectMapper()
mapper.registerModule(DefaultScalaModule)

println(mapper.writeValueAsString(brands))
// ==> [{"name":"Coke"},{"name":"Disney"}]
println(mapper.writeValueAsString(brandCount))
// ==> {"Brand(Coke)":5,"Brand(Disney)":10}

我能想到的最好办法是为Brand 定义一个自定义序列化程序和密钥序列化程序:

import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.core.JsonGenerator

class BrandSerializer extends JsonSerializer[Brand] {
  override def serialize(
    b: Brand,
    json: JsonGenerator,
    provider: SerializerProvider
  ): Unit = {
    json.writeString(b.name)
  }
}

class BrandKeySerializer extends JsonSerializer[Brand] {
  override def serialize(
    b: Brand, 
    json: JsonGenerator,
    provider: SerializerProvider
  ): Unit = {
    json.writeFieldName(b.name)
  }
}

val serializers = new SimpleModule("Serializers");
serializers.addSerializer(classOf[Brand], new BrandSerializer())
serializers.addKeySerializer(classOf[Brand], new BrandKeySerializer());

val mapper = new ObjectMapper()
mapper.registerModule(DefaultScalaModule)
mapper.registerModule(serializers)

println(mapper.writeValueAsString(brands))
// ==> ["Coke","Disney"]
println(mapper.writeValueAsString(brandCount))
// ==> {"Coke":5,"Disney":10}

有没有更好(或更简洁)的方法将这些值类(或任何 case 类)序列化为字符串?

【问题讨论】:

  • 是否需要使用jackson?
  • 是的,我正在使用一个使用 Jackson 呈现 HTTP JSON 响应的框架。

标签: json scala serialization jackson


【解决方案1】:

嗯,我不认为,有一种方法可以让它随心所欲地做,而且一次性没有你不想要的东西...... 你能想到的最好的事情就是用Product1替换Brand,用b._1替换b.name(我也认为,你的密钥序列化器是错误的——它应该写出b.getClass.getSimpleName,而不是不是b.name)。

这不会减少写出单个类的冗长,但至少会消除为每种类型创建单独的序列化程序的需要。

当然,缺点是每个单字段案例类最终都会以这种方式编写,这可能比您希望的要多..

【讨论】:

    猜你喜欢
    • 2013-11-09
    • 1970-01-01
    • 2018-03-17
    • 2020-05-20
    • 1970-01-01
    • 2016-01-02
    • 1970-01-01
    • 2015-10-25
    • 1970-01-01
    相关资源
    最近更新 更多