2
votes

I am using Gson to serialize and deserialize objects, and saving the results in Redis. ie object is serialized into json string then put in Redis, when the object is retreived, it is string then I use Gson.fromjson(str, className) to deserialize into object.

I am beginner with Scala so I assume my usage is incorrect.

I have the following class:

case class Status(id: String, state: State)

where State is the following:

sealed trait State {}

case object COMPLETED_SUCCESSFULLY extends State {}

case object FINISHED_POLLING extends State {}

case object CURRENTLY_DOWNLOADING extends State {}

case object FINISHED_DOWNLOADING extends State {}

case object CURRENTLY_UPLOADING extends State {}

case object FINISHED_UPLOADING extends State {}

I want to serialize Status into a json string then deserialize it back into an object.

But, when I serialize Status using Gson, I get:

"{\"id\":\"foo\",\"state\":{}}"

Why is that?

Ex:

val Status = new Status("foo", COMPLETED_SUCCESSFULLY)

I expect the serialized output to be

"{\"id\":\"foo\",\"state\":\"COMPLETED_SUCCESSFULLY\"}"
1
What output do you expect? - ka4eli
@ka4eli updated question. I just want to be able to serialize and deserialize using gson. - iCodeLikeImDrunk

1 Answers

6
votes

By default, case objects are serialized by Gson to empty json objects: {}. You have to write custom serializer to get expected behaviour:

object StateSerializer extends JsonSerializer[State] {
  override def serialize(t1: State, t2: Type, jsonSerializationContext: JsonSerializationContext): JsonElement = {
    val res = new JsonObject()
    res.add("name", new JsonPrimitive(t1.toString))
    res
  }
}


val gson = new GsonBuilder().registerTypeHierarchyAdapter(classOf[State], StateSerializer)
.registerTypeHierarchyAdapter(classOf[State], StateDeserializer).setPrettyPrinting().create()

println(gson.toJson(COMPLETED_SUCCESSFULLY))  

Will print:

{
  "name": "COMPLETED_SUCCESSFULLY"
}

Also if you want to transform json to case object you have to implement JsonDeserializer:

object StateDeserializer extends JsonDeserializer[State] {
  override def deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): State = {
    val res = json match {
      case o: JsonObject if o.has("name") && o.entrySet().size() == 1 =>
        val name = o.get("name").getAsString
        name match {
          case "FINISHED_POLLING" => FINISHED_POLLING
          case "FINISHED_DOWNLOADING" => FINISHED_DOWNLOADING
          case "FINISHED_UPLOADING" => FINISHED_UPLOADING
          case "CURRENTLY_DOWNLOADING" => CURRENTLY_DOWNLOADING
          case "CURRENTLY_UPLOADING" => CURRENTLY_UPLOADING
          case "COMPLETED_SUCCESSFULLY" => COMPLETED_SUCCESSFULLY
          case _ => null
        }
      case _ => null
    }

    Option(res).getOrElse(throw new JsonParseException(s"$json can't be parsed to State"))
  }
}

println(gson.fromJson("{\"name\": \"COMPLETED_SUCCESSFULLY\"}", classOf[State])) 

Will print:

COMPLETED_SUCCESSFULLY