Overview

This plugin allows you to use Google's Gson to convert Java Objects into JSON and back.

It provides an implementation of JsonManager which is a component required in any Spincast application. The default implementation uses Jackson... The Gson implementation provided by this plugin is a replacement.

Please note that this Gson implementation is not as well tested as the default Jackson one. We do recommend you stick with the default Jackson plugin if you want the easiest solution. But if you do use this Gson plugin, we are very open to comments/suggestions to improve it!

Introduction

Gson is a library developed by Google and allows the conversion of Java Objects into JSON and back.

Some people prefer Gson to Jackson for such a task. Gson documentation is indeed good, its performances are good and creating custom (de)serializers is easy.

But, in our opinion, working with Gson is sometimes harder than with Jackson. For example, you can't use getters to specify values to serialize. Also, there is an annoying issue when a child class declares a field with the same name as a field in its base class.

Finally, you will probably have to use the transient keyword (or use the @Expose annotation provided by Gson) often... Otherwise, you can easily get a StackOverflowError exception when Gson encounters circular references.

It seems to us Jackson deals better with those situations.

Usage

Extending SpincastGsonManager

As you will see in the installation section, the first step to use Gson in a Spincast application is to replace the default Jackson plugin.

When this is done, you extend SpincastGsonManager to get control over how Gson is configured:

public class AppGsonManager extends SpincastGsonManager {
    // ...
}

In your Guice module, you then bind this class as the JsonManager implementation to use:


bind(JsonManager.class).to(AppGsonManager.class).in(Scopes.SINGLETON);

You now can override all the methods this plugin uses to configure Gson...

The most interesting of those methods is probably configureGsonBuilder(...). By overriding this method, you get access to the GsonBuilder and you can tweak or add anything you need:

@Override
protected void configureGsonBuilder(GsonBuilder gsonBuilder) {
    super.configureGsonBuilder(gsonBuilder);
    
    // Add your custom configurations
    gsonBuilder.registerTypeHierarchyAdapter(MyClass.class, new MyClassSerializer());
}

You can also override some methods to prevent default behaviors. For example, if you don't want the plugin to automatically add one of its custom serializers, you can simply override the method that adds it:

@Override
protected void registerDateSerializer(GsonBuilder gsonBuilder) {
    // Disable the custom Date serializer
    // *do nothing here*
}

Using a custom JsonManager interface

If you need to use methods provided by Gson but not available through the JsonManager interface, you can also create a custom interface and add those methods to it.

You first create a custom interface by extending JsonManager and by adding the extra methods to it:

public interface AppJsonManager extends JsonManager {

    // Return the Gson instance
    public Gson getGson();

    // Convert a typed object to a JsonObject
    public JsonObject fromObject(Object object, Type typeOfSrc);
}

You then make your AppGsonManager implementation extend this custom interface, and still extend the base SpincastGsonManager class provided by this plugin:

public class AppGsonManager extends SpincastGsonManager implements AppJsonManager {

    @Inject
    public AppJsonManagerDefault(JsonDeserializer<JsonObject> jsonObjectDeserializer,
                                 JsonDeserializer<JsonArray> jsonArrayDeserializer,
                                 JsonSerializer<JsonObject> jsonObjectSerializer,
                                 JsonSerializer<JsonArray> jsonArraySerializer,
                                 JsonSerializer<Date> dateSerializer,
                                 JsonSerializer<Instant> instantSerializer,
                                 JsonSerializer<BigDecimal> bigDecimalSerializer,
                                 JsonSerializer<Enum<?>> enumSerializer,
                                 JsonSerializer<Class<?>> classSerializer,
                                 JsonPathUtils jsonPathUtils,
                                 JsonObjectFactory jsonObjectFactory,
                                 SpincastConfig spincastConfig,
                                 SpincastUtils spincastUtils,
                                 FormFactory formFactory,
                                 Provider<Injector> guiceProvider) {
        super(jsonObjectDeserializer,
              jsonArrayDeserializer,
              jsonObjectSerializer,
              jsonArraySerializer,
              dateSerializer,
              instantSerializer,
              bigDecimalSerializer,
              enumSerializer,
              classSerializer,
              jsonPathUtils,
              jsonObjectFactory,
              spincastConfig,
              spincastUtils,
              formFactory,
              guiceProvider);
    }
    
    // The "getGson()" method is already provided by the base class!
    // public Gson getGson();

    // Typed version for "fromObject()"
    @Override
    public JsonObject fromObject(Object object, Type typeOfSrc) {
        if (object == null) {
            return null;
        }

        String json = getGson().toJson(object, typeOfSrc);
        JsonObject jsonObject = fromString(json);
        return jsonObject;
    }

Finally, you bind all the required components to your Guice module:


bind(AppGsonManager.class).in(Scopes.SINGLETON);
bind(JsonManager.class).to(AppGsonManager.class).in(Scopes.SINGLETON);
bind(AppJsonManager.class).to(AppGsonManager.class).in(Scopes.SINGLETON);

Remember that Spincast requires the JsonManager interface to be bound to an implementation! So you need to bind both JsonManager and AppJsonManager interfaces to the same instance. Then, in your application code, you inject AppJsonManager instead of JsonManager to get access to the extra methods.

Custom serializers

This plugin provides some custom serializers and deserializers for Gson to use. As we showed previously, you can disable/change them if required.

They are:

Installation

Note that since this plugin replaces a default one, you must first disable the default before adding it.

1. Add this Maven artifact to your project:

<dependency>
    <groupId>org.spincast</groupId>
    <artifactId>spincast-plugins-gson</artifactId>
    <version>1.14.1</version>
</dependency>

2. Disable the default Jackson Json plugin from your Spincast Bootstrapper by calling disableDefaultJsonPlugin():


Spincast.configure()
        .disableDefaultJsonPlugin()
        // ...

3. Add an instance of the SpincastGsonPlugin plugin :


Spincast.configure()
        .disableDefaultJsonPlugin()
        .plugin(new SpincastGsonPlugin())
        // ...