Using GSON as an alternative to XStream/Jettison in a JSON/Java messaging system

1,091 views
Skip to first unread message

Doug Daniels

unread,
May 12, 2009, 1:38:34 AM5/12/09
to google-gson
I've been using XStream and Jettison to provide a way to convert Java
objects to and from JSON to be handled on javascript AJAX clients.

Over time there's been alot of issues that have come up with using
XStream and JETTISON (the way that lists of objects are represented in
XStream JETTISON are completely non-intuitive for client-side
javascript to parse or produce).

I'm looking for another JSON library and GSON looks promising. I'm
running into an issue though with being able to serialize a JSON
object and deserialize it in GSON when that object is a concrete
Message subclass and I only know to expect an instanceof "Message".
For example this fails in GSON:


class MockMessage {
int val = 1;
}
class MockMessageOther extends MockMessage {
int otherVal = 1;
}


public static void main(String[] args) {
Gson gson = new Gson();

MockMessage mock1 = new MockMessage();
MockMessage mock2 = new MockMessage();
MockMessageOther mock3 = new MockMessageOther();

List<MockMessage> messages = new ArrayList<MockMessage>();
messages.add(mock1);
messages.add(mock2);
messages.add(mock3);

String jsonString = gson.toJson(messages);

//JSON list format is non-intuitive single element array with
class name fields
System.out.println(jsonString);
List gsonJSONUnmarshalledMessages = (List)gson.fromJson
(jsonString, List.class);
//This will print 3 messages unmarshalled
System.out.println("XStream format JSON Number of messages
unmarshalled: " + gsonJSONUnmarshalledMessages.size());
}

In the GSON FAQ it states:

"Collections Limitations

* Can serialize collection of arbitrary objects but can not
deserialize from it
o Because there is no way for the user to indicate the type
of the resulting object
* While deserializing, Collection must be of a specific generic
type

All of this makes sense, and is rarely a problem when following good
Java coding practices "

Is my generic messaging system breaking some "good Java coding
practices" and if so what other alternatives do I have for
implementing a system like this using GSON, I was able to get away
with it in XStream because type information is embedded in every
serialized object.

You can see a further discussion of XStream/Jettison and alternative
JSON to Java libraries on StackOverflow:
http://stackoverflow.com/questions/836805/in-xstream-is-there-a-better-way-to-marshall-unmarshall-listobjects-in-json-and

inder

unread,
May 12, 2009, 1:53:44 PM5/12/09
to google-gson
Hi Doug,

You will have to write a custom deserializer for MockMessage that will
look at the JsonObject and create the subclasses if needed.
Gson will then be able to insert them automatically in the collection
and you will have your collection of (somewhat) arbitrary objects.

Let us know if you need further help on this.
Inder
>  http://stackoverflow.com/questions/836805/in-xstream-is-there-a-bette...

Doug Daniels

unread,
May 12, 2009, 2:28:47 PM5/12/09
to googl...@googlegroups.com
Is there a way to not have to write a custom serializer each time you add a new type of Message subclass. For example could you have a generic reflection serializer that puts the name of the class as one of the fields of the JSON object for example:

{
  className: "com.test.MockMessage2"
...
}

Then have a generic reflection deserializer that would read that className and use reflection to deserialize the other fields and objects.

inder

unread,
May 12, 2009, 2:52:39 PM5/12/09
to google-gson
At the moment, Gson doesn't let you register a custom deserializer for
a class and all of its subtypes.
This is something we have considered adding but haven't done so yet.

As I understand your requirements, you don't need to write a custom
deserializer per sub-class. You will be writing a single deserializer
for MockMessage. Here is how it would look like:

public class MyMockMessageDeserializer implements
JsonDeserializer<MockMessage> {

public MockMessage deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) {
JsonObject obj = json.getAsJsonObject();
String className = obj.get("className");
// Get other properties from obj that are needed to create the
instance for MockMessage
MockMessage msg = // Create an instance of the proper subtype
based on className
return msg;
}
}



On May 12, 11:28 am, Doug Daniels <daniels.doug...@gmail.com> wrote:
> Is there a way to not have to write a custom serializer each time you add a
> new type of Message subclass. For example could you have a generic
> reflection serializer that puts the name of the class as one of the fields
> of the JSON object for example:
>
> {
>   className: "com.test.MockMessage2"
> ...
>
> }
>
> Then have a generic reflection deserializer that would read that className
> and use reflection to deserialize the other fields and objects.
>

Doug Daniels

unread,
May 12, 2009, 3:04:19 PM5/12/09
to googl...@googlegroups.com
Looks good i'll try that out, in fact what you just proposed does look like a way to deserialize for a class and all its subtypes, if I use the obj.get("className") and then inspect the rest of the fields in the JSON object and set them using reflection it would allow me to handle all subclasses of Message.
Reply all
Reply to author
Forward
0 new messages