Serializer for parameterized types (in Scala)

640 views
Skip to first unread message

Marcus Downing

unread,
Feb 19, 2011, 8:53:59 PM2/19/11
to googl...@googlegroups.com
Gson works really well in Scala, as long as you stick to the types it's aware of - Int, String, Array, etc. Use var rather than val and make sure there's a no-args constructor:

class MyType(var title: String, var foo: Int) {
    def this() = this("", 0)
}

Out of the box, Gson doesn't know about Scala types like List, nor does it know about Joda times. I'm trying to add some custom serialization handlers, as suggested in the user guide, but I hit an issue when it comes to Option. Option is a container like an array or list, but it can either contain one value, in which case it's called Some(x), or None. I tried adding a custom serializer for Option, like so:

    object OptionSerializer extends JsonSerializer[Option[_]] with JsonDeserializer[Option[_]] {
        def serialize(src: Option[_], typeOfT: Type, context: JsonSerializationContext) =
            src match {
                case Some(v) => context.serialize(v, typeOfT)
                case None => null
            }
        def deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext) =
            json match {
                case null => None
                case _ if json.isJsonNull => None
                case _ => Some(context.deserialize(json, typeOfT))
            }
    }

    builder.registerTypeAdapter(classOf[Option[_]], OptionSerializer)

The problem is with the typeOfT parameter. At runtime this appears to be a com.google.gson.ParameterizedTypeImpl. How do I convert that to the inner type that needs to be passed in?

Marcus Downing

unread,
Feb 19, 2011, 9:02:23 PM2/19/11
to googl...@googlegroups.com
d'oh. That was easier than I thought. com.google.gson.ParameterizedType implements java.lang.reflect.ParameterizedType, so all I needed to do was call getActualTypeArguments on it.


    object OptionSerializer extends JsonSerializer[Option[_]] with JsonDeserializer[Option[_]] {
        def innerType(outerType: Type) = outerType match {
            case pt: ParameterizedType => pt.getActualTypeArguments()(0)
            case _ => throw new UnsupportedOperationException(outerType.toString)
        }

        def serialize(src: Option[_], typeOfT: Type, context: JsonSerializationContext) =
            src match {
                case Some(v) => println(typeOfT.toString); context.serialize(v, innerType(typeOfT))
                case None => null
            }
        def deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext) =
            json match {
                case null => None
                case _ if json.isJsonNull => None
                case _ => println(typeOfT.toString); Some(context.deserialize(json, innerType(typeOfT)))
            }
    }

And I now have Option[LocalDate] working nicely. 

Joel

unread,
Apr 13, 2011, 5:48:43 AM4/13/11
to google-gson
And with Gson 1.7 there is no need for a no-args constructor on your
types.

Marcus Downing

unread,
Apr 13, 2011, 7:25:54 AM4/13/11
to googl...@googlegroups.com
Good to know.
Reply all
Reply to author
Forward
0 new messages