30

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...?

Moshe Bixenshpaner
  • 1,840
  • 1
  • 17
  • 23
  • Aside from how (which is answered), curious as to why? There are already 4 alternative methods. So what does Gson bring above and beyond Jackson and Jettison? – StaxMan Mar 01 '12 at 16:47
  • 5
    IMHO with Gson it's much easier to control the structure/format of the JSON if you can't or don't want to annotate the hell out of your model classes (compared to Jackson). – Philipp Reichart Mar 01 '12 at 17:12
  • 1
    There are many reasons: First of all, according to recent benchmarks, Jackson is slower. Second, it enforces you to annotate classes, rather than simply use POJOs just the way they are. Third, Gson serializes the entire object, and not just the public fields (as in good design practice, you get to have many important non-public fields). – Moshe Bixenshpaner Mar 04 '12 at 13:09
  • 1
    @StaxMan One of the reasons could be that Jackson ObjectMapper causes core dump in JDK 1.8 – Krzysztof Krasoń Apr 17 '14 at 15:20
  • @krzyk not that I won't believe you but I haven't seen reports of this; and without bug reports things can't be fixed. Nor are they credible complaints IMO. – StaxMan Apr 23 '14 at 18:27
  • 1
    @MosheBixenshpaner links please to slowness -- I have not seen any. Gson has been improving (2.1 is decent), but still lagging from all I have seen. Jackson absolute does not require annotations (plus, mix-in annotations can be used to avoid annotation value classes) for most cases. Last: Jackson does not require public fields; but either getters, or changing of default visibility -- I disagree in that serializing all private fields by default is good practice; but if one wants it, perfectly doable with Jackson. – StaxMan Apr 23 '14 at 18:30
  • 1
    @StaxMan See https://bugs.openjdk.java.net/browse/JDK-8035399 – Krzysztof Krasoń Apr 24 '14 at 20:51
  • @StaxMan, http://blog.takipi.com/the-ultimate-json-library-json-simple-vs-gson-vs-jackson-vs-json/ Clearly, for the *average* object responses (~1k), GSON wins the competition. – Moshe Bixenshpaner Jan 23 '16 at 08:24
  • @MosheBixenshpaner Please read comments at that measurement -- it is badly written, measuring noise if anything. I am not objecting to findings, but the flaws in measurement methodology. I have not seen anything credible to suggest GSON would be significantly faster than Jackson for messages of any size, although there are many cases where speed differences are negligible (within 10-20% range). – StaxMan Jan 26 '16 at 21:43
  • This link might help you how to do serialize/deserializing using gson : http://eclipsesource.com/blogs/2012/11/02/integrating-gson-into-a-jax-rs-based-application/ – Balaji Boggaram Ramanarayan Nov 05 '14 at 02:18

5 Answers5

26

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> { ...
Philipp Reichart
  • 20,771
  • 6
  • 58
  • 65
  • 3
    I already have such a provider, but for some reason, it still uses Jackson (I use Glassfish 3.1.1 if that helps). – Moshe Bixenshpaner Mar 01 '12 at 15:12
  • How to you register your GsonProvider with Jersey? Does your server output something like `Provider classes found: your.provider.class.name` on startup? – Philipp Reichart Mar 01 '12 at 15:55
  • Does your provider get invoked and maybe returns something that tells Jersey it's not compatible? Try adding breakpoints on all methods in your provider class. – Philipp Reichart Mar 01 '12 at 15:56
21

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();
        }
    }
}
DominikAngerer
  • 6,354
  • 5
  • 33
  • 60
  • Been using this, works great but... why the `type.equals(genericType)` ? Seems to be that you can always use `Type` as gson supports it and has more information than the `Class`. – sargue Apr 09 '15 at 18:09
  • You're right - the `genericType` should be used instead of the equals check - you can create a pull request on github if you like. I also will test it with my test cases as well and then edit my answer. – DominikAngerer Apr 09 '15 at 23:24
  • thanks @sargue for the update of the GsonJerseyProvider - I have updated the copy&paste solution in here - you can find a running example directly under the github link. – DominikAngerer Apr 11 '15 at 15:30
3

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:

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.

Jasper de Vries
  • 19,370
  • 6
  • 64
  • 102
1

You should solve just adding this dependency in your pom

<dependency>
    <groupId>org.zalando.phrs</groupId>
    <artifactId>jersey-media-json-gson</artifactId>
    <version>0.1</version>
</dependency>

Here you can find the repo with the source code: https://github.com/zalando/jersey-media-json-gson

1

one eternity later....
You can use the real dependency jersey media gson

<dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-gson</artifactId>
        <version>${jersey.version}</version>
</dependency>

the class to registrer is:

JsonGsonFeature.class
Micky C.
  • 21
  • 4