JAX-RS Jersey Gson Serializer and Deserializer
This tutorial shows how to use Gson
to marshal and unmarshal a Java object to and from JSON
representation. You could also use the default implementations like: Jackson
, JSONP
or MOXy
. But the power of using Gson
, is that it doesn’t require any annotations on your classes and thus can work with any third party libraries, which you don’t have the source code of.
Jersey does not support Gson by default. But in the following example we show you how you can support it. We make efficient use of the MessageBodyReader
and MessageBodyWriter
to support Gson
to make the conversions between Java and JSON.
Dependencies
First, make sure that the Gson library is on your class path. When using maven, you can add the following maven dependencies.
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.22.2</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.6.2</version>
</dependency>
Custom JAX-RS Jersey GsonProvider
Next, we are creating a Gson Provider to serialize and deserialize a JSON String to and from a Java Object.
The MessageBodyReader
is used to deserialize the JSON string into a Java object. We can use the isReadable()
method to manage whether the class is eligible for deserialization. Using the readFrom()
method, we can convert the InputStream
into a Java object.
The MessageBodyWriter
is used to serialize a Java object into a JSON String representation. We can use the isWriteable()
method to manage whether the class is eligible for serialization. Using the writeTo
method, we can serialize the Java object into a JSON representation. Note that we also injected the UriInfo
, this allows us to inspect the query parameters. We search for a query parameter named “pretty-print”. When this query parameter is found, we use a different Gson
object to return the ‘pretty’ JSON String, which is more human readable.
Finally, we annotate the GsonProvider
with the @Provider
annotation, in order to tell Jersey to automatically register this class. The @Produces
and @Consumes
annotations are used to tell the provider which media types it supports.
package com.memorynotfound.jaxrs.gson;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
@Provider
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class GsonProvider<T> implements MessageBodyReader<T>, MessageBodyWriter<T> {
private static final String PRETTY_PRINT = "pretty-print";
private final Gson gson;
private final Gson prettyGson;
@Context
private UriInfo ui;
public GsonProvider() {
GsonBuilder builder = new GsonBuilder()
.serializeNulls()
.enableComplexMapKeySerialization();
this.gson = builder.create();
this.prettyGson = builder.setPrettyPrinting().create();
}
@Override
public boolean isReadable(Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return true;
}
@Override
public T readFrom(Class<T> type, Type genericType, Annotation[] annotations,
MediaType mediaType, MultivaluedMap<String, String> httpHeaders,
InputStream entityStream) throws IOException, WebApplicationException {
InputStreamReader reader = new InputStreamReader(entityStream, "UTF-8");
try {
return gson.fromJson(reader, type);
} finally {
reader.close();
}
}
@Override
public boolean isWriteable(Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return true;
}
@Override
public long getSize(T t, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return -1;
}
@Override
public void writeTo(T t, Class<?> type, Type genericType, Annotation[] annotations,
MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
OutputStream entityStream) throws IOException, WebApplicationException {
PrintWriter printWriter = new PrintWriter(entityStream);
try {
String json;
if (ui.getQueryParameters().containsKey(PRETTY_PRINT)){
json = prettyGson.toJson(t);
} else {
json = gson.toJson(t);
}
printWriter.write(json);
printWriter.flush();
} finally {
printWriter.close();
}
}
}
We are configuring Jersey without a web.xml servlet descriptor. By using the @ApplicationPath
annotation, Jersey is automatically configured and searches automatically for any other @Provider
annotations.
package com.memorynotfound.jaxrs.gson;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import java.util.HashMap;
import java.util.Map;
@ApplicationPath("/api")
public class ApplicationConfig extends Application {
}
The following rest resource returns a simple Health
object.
package com.memorynotfound.jaxrs.gson;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@Path("/health")
public class HealthResource {
@GET
public Health getHealth(){
return new Health("hostname", "123.123.123.123");
}
}
The following Java object will be serialized and deserialized using Gson
. The power of Gson is that your object doesn’t need any special annotations in order to make it eligible for JSON processing. This makes it ideal to work with third party libraries.
package com.memorynotfound.jaxrs.gson;
import java.lang.management.ManagementFactory;
public class Health {
private String hostname;
private String ip;
private long startTime;
private long upTime;
public Health(String hostname, String ip) {
this.hostname = hostname;
this.ip = ip;
this.startTime = ManagementFactory.getRuntimeMXBean().getStartTime();
this.upTime = ManagementFactory.getRuntimeMXBean().getUptime();
}
}
Demo
URL: http://localhost:8081/jaxrs-gson/api/health
URL: http://localhost:8081/jaxrs-gson/api/health?pretty-print
This is cool. Is there a github URL where I can see the full source? Thanks