Custom marshalling with Gson - part 2

My original motivation for this series of posts was the “new” 1.10 release of jQuery DataTables. This release added client-side processing with data delivery as json objects via ajax – a great match for a jersey back end. The Ajax data source (objects) requires that the data be provided with a key of “data” and a value of an array of objects. I’ll update our project to provide the UserMap in that format.

Here’s the UserMapMarshall class implementing JsonSerializer. First it creates an array of json objects from the UserMap values and then it creates a json object with a key of “data” and a value of the array. The Gson object is thread-safe, so it’s safe to retain as a static member.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.ideoplex.tutorial;


import java.lang.reflect.Type;

import java.util.Collection;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonElement;
import com.google.gson.JsonSerializer;
import com.google.gson.JsonSerializationContext;


public class UserMapMarshall implements JsonSerializer<UserMap> {
private static Gson gson = new Gson();

@Override
public JsonElement serialize(UserMap map , Type typeOfSrc, JsonSerializationContext context) {
JsonArray array = new JsonArray();
for ( User user : map.values() ) {
array.add( gson.toJsonTree(user) );
}

JsonObject object = new JsonObject();
object.add("data",array);

return object;
}

}

The GsonWriter class was also updated to save the Gson object as a static member. In this case, the Gson object was generated from a GsonBuilder object and an UserMapMarshall object explicitly registered as the Type Adapter for the UserMap class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
$ git diff --staged GsonWriter.java                                                                      Amber  6:15
diff --git a/src/main/java/com/ideoplex/tutorial/GsonWriter.java b/src/main/java/com/ideoplex/tutorial/GsonWriter.java
index 990b5dd..9ef181d 100644
--- a/src/main/java/com/ideoplex/tutorial/GsonWriter.java
+++ b/src/main/java/com/ideoplex/tutorial/GsonWriter.java
@@ -25,12 +25,16 @@ import javax.ws.rs.ext.MessageBodyWriter;


import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;


@Provider
@Produces(MediaType.APPLICATION_JSON)
@Singleton
public class GsonWriter<T> implements MessageBodyWriter<T> {
+ protected static Gson gson = new GsonBuilder()
+ .registerTypeAdapter(UserMap.class,new UserMapMarshall())
+ .create();

@Override
public void writeTo(T t, Class<?> type, Type genericType,
@@ -38,9 +42,8 @@ public class GsonWriter<T> implements MessageBodyWriter<T> {
MultivaluedMap<String, Object> httpHeaders,
OutputStream entityStream)
throws IOException, WebApplicationException {
- Gson g = new Gson();
httpHeaders.get("Content-Type").add("charset=UTF-8");
- entityStream.write(g.toJson(t).getBytes("UTF-8"));
+ entityStream.write(gson.toJson(t).getBytes("UTF-8"));
}

@Override

After deploying the new webapp, the first request returns “data” as the key and an empty array as the value.

1
2
$ curl http://xxxxxx-nnnnnn.use1-2.nitrousbox.com:8080/jersey-gson/webapi/myresource/user/map         
{"data":[]}

I insert two new User objects.

1
2
3
4
5
6
7
8
$ curl http://xxxxxx-nnnnnn.use1-2.nitrousbox.com:8080/jersey-gson/webapi/myresource/user/post \
--header 'Content-type: application/json' \
--data '{"email":"noone@example.com","surName":"Doe","givenName":"John"}'
{"email":"noone@example.com","surName":"Doe","givenName":"John"}
$ curl http://xxxxxx-nnnnnn.use1-2.nitrousbox.com:8080/jersey-gson/webapi/myresource/user/post \
--header 'Content-type: application/json' \
--data '{"email":"john@example.com","surName":"Public","givenName":"John"}'
{"email":"john@example.com","surName":"Public","givenName":"John"}

And now the response object with “data” as the key and an array of User objects as the value – formatted for clarity.

1
2
3
4
$ curl http://xxxxxx-nnnnnn.use1-2.nitrousbox.com:8080/jersey-gson/webapi/myresource/user/map
{"data":[{"email":"john@example.com","surName":"Public","givenName":"John"},
{"email":"noone@example.com","surName":"Doe","givenName":"John"}
]}

Next, I’ll connect this to an html page with a DataTable. You can browse the source for jersey-gson on GitHub.

29 Sep: Custom Marshalling with Gson - part 1
04 Oct: Jersey, Gson and DataTables