Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Gson instead of Jackson in Jersey

I have a RESTful service that consumes and produces JSON objects, and I would like Jersey to use Gson instead of Jackson.

How can this be done...?

like image 500
Moshe Bixenshpaner Avatar asked Mar 01 '12 12:03

Moshe Bixenshpaner


People also ask

Does Jersey use Jackson?

Jersey uses Jackson internally to convert Java objects to JSON and vice versa.

Is Gson faster than Jackson?

Last benchmarks Jackson was the winner, but this time GSON is by far the fastest, with JSONP being a close second and then followed by Jackson and then JSON.

Is Gson deprecated?

Gson is not deprecated.

What is the difference between JSON and Gson?

GSON can use the Object definition to directly create an object of the desired type. While JSONObject needs to be parsed manually.


3 Answers

You need to write custom implementations of MessageBodyReader and MessageBodyWriter (possibly in the same class) and register with Jersey (if you use package scanning, the @Provider annotation is enough) -- pretty much like JacksonJsonProvider does it:

@Provider
@Consumes({MediaType.APPLICATION_JSON, "text/json"})
@Produces({MediaType.APPLICATION_JSON, "text/json"})
class GsonJsonProvider implements
    MessageBodyReader<Object>,
    MessageBodyWriter<Object> { ...
like image 169
Philipp Reichart Avatar answered Oct 22 '22 10:10

Philipp Reichart


You can find a fully working example here: https://github.com/DominikAngerer/java-GsonJerseyProvider

There will be an working implementation of http://eclipsesource.com/blogs/2012/11/02/integrating-gson-into-a-jax-rs-based-application/ but with some new achievements - like an GsonUtil for Expose only things.

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;

@Provider
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class GsonJerseyProvider implements MessageBodyWriter<Object>,
        MessageBodyReader<Object> {

    private static final String UTF_8 = "UTF-8";

    @Override
    public boolean isReadable(Class<?> type, Type genericType,
            java.lang.annotation.Annotation[] annotations, MediaType mediaType) {
        return true;
    }

    @Override
    public Object readFrom(Class<Object> type, Type genericType,
            Annotation[] annotations, MediaType mediaType,
            MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
            throws IOException {
        InputStreamReader streamReader = new InputStreamReader(entityStream,
                UTF_8);
        try {
            return GsonUtil.getInstance().fromJson(streamReader, genericType);
        } catch (com.google.gson.JsonSyntaxException e) {
            // Log exception
        } finally {
            streamReader.close();
        }
        return null;
    }

    @Override
    public boolean isWriteable(Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType) {
        return true;
    }

    @Override
    public long getSize(Object object, Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType) {
        return -1;
    }

    @Override
    public void writeTo(Object object, Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType,
            MultivaluedMap<String, Object> httpHeaders,
            OutputStream entityStream) throws IOException,
            WebApplicationException {
        OutputStreamWriter writer = new OutputStreamWriter(entityStream, UTF_8);
        try {
            GsonUtil.getInstance().toJson(object, genericType, writer);
        } finally {
            writer.close();
        }
    }
}
like image 39
DominikAngerer Avatar answered Oct 22 '22 12:10

DominikAngerer


Payara 4

I had a hard time to get my custom Gson @Provider working with Jersey embedded in GlassFish / Payara. In that case you must set the property jersey.config.server.disableMoxyJson to true.

For example:

@ApplicationPath("/api")
public class MyApplication extends Application {
    @Override
    public Map<String, Object> getProperties() {
        Map<String, Object> props = new HashMap<>();
        props.put("jersey.config.server.disableMoxyJson", true);
        return props;
    }
}

See also:

  • https://jersey.github.io/documentation/latest/appendix-properties.html
  • Customizing JSON marhsalling with GlassFish v4

Same thing goes for a Jersey client:

new ClientConfig()
        .register(MyGsonProvider.class)
        .property("jersey.config.client.disableMoxyJson", true);

Payara 5

Payara 5 supports the JSON Binding API, so it does not make sense to keep using Gson. I would advice to migrate to JSON-B.

like image 3
Jasper de Vries Avatar answered Oct 22 '22 11:10

Jasper de Vries