You can define generic serializer and deserializer for all enums and then for each of them register corresponding pairs of instances:
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))
...
)
}
}
The proposed solution is much safe and more efficient in runtime than just using of Status.withName(s)
for each deserialization.
It will work even for the dynamic definition of enum values, like:
object Status extends Enumeration {
type Status = Value
val Success = Value
val Error = Value
def extra(name: String): Status = Value(nextId, name)
}
Status.extra("Unknown")
Full sources are here.