templates.plugins.spincast-gson.spincast-gson.html Maven / Gradle / Ivy
Show all versions of spincast-website Show documentation
{% extends "../../layout.html" %}
{% block sectionClasses %}plugins hasBreadCrumb plugins-spincast-gson{% endblock %}
{% block meta_title %}Plugins - Spincast Gson{% endblock %}
{% block meta_description %}Spincast Gson plugin - JSON Serialization / Deserialization{% endblock %}
{% block scripts %}
{% endblock %}
{% block body %}
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:
{% verbatim %}
public class AppGsonManager extends SpincastGsonManager {
// ...
}
{% endverbatim %}
In your Guice module, you then bind this class as the JsonManager
implementation to use:
{% verbatim %}
bind(JsonManager.class).to(AppGsonManager.class).in(Scopes.SINGLETON);
{% endverbatim %}
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:
{% verbatim %}
@Override
protected void configureGsonBuilder(GsonBuilder gsonBuilder) {
super.configureGsonBuilder(gsonBuilder);
// Add your custom configurations
gsonBuilder.registerTypeHierarchyAdapter(MyClass.class, new MyClassSerializer());
}
{% endverbatim %}
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:
{% verbatim %}
@Override
protected void registerDateSerializer(GsonBuilder gsonBuilder) {
// Disable the custom Date serializer
// *do nothing here*
}
{% endverbatim %}
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:
{% verbatim %}
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);
}
{% endverbatim %}
You then make your AppGsonManager
implementation extend this custom interface, and still extend the base
SpincastGsonManager
class provided by this plugin:
{% verbatim %}
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;
}
{% endverbatim %}
Finally, you bind all the required components to your Guice module:
{% verbatim %}
bind(AppGsonManager.class).in(Scopes.SINGLETON);
bind(JsonManager.class).to(AppGsonManager.class).in(Scopes.SINGLETON);
bind(AppJsonManager.class).to(AppGsonManager.class).in(Scopes.SINGLETON);
{% endverbatim %}
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:
-
JsonObjectSerializer
and JsonObjectDeserializer
Those are for (de)serializing Spincast's JsonObjects.
-
JsonArraytSerializer
and JsonArrayDeserializer
Those are for (de)serializing Spincast's JsonArrays.
-
BigDecimalSerializer
This serializes BigDecimal
objects by calling their .toPlainString() method.
-
ClassSerializer
This serializes Class
objects by calling their .getName() method.
-
DateSerializer
This serializes Date
objects by converting them to the ISO-8601
format using
a SpincastStatics utility.
-
EnumSerializer
This serializes Enumeration values
to a JsonObject
containing their
name() (as a
"name" field) and
toString() (as a
"label" field).
Here's an example of what a serialized enum could look like, given it provides an human readable toString()
value:
{% verbatim %}
{
"name": "BLUE",
"label": "The color blue"
}
{% endverbatim %}
-
InstantSerializer
This serializes Instant
objects by calling their .toString() method.
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>{{spincast.spincastCurrrentVersion}}</version>
</dependency>
2. Disable the default Jackson Json plugin from your Spincast Bootstrapper
by calling disableDefaultJsonPlugin():
{% verbatim %}
Spincast.configure()
.disableDefaultJsonPlugin()
// ...
{% endverbatim %}
3. Add an instance of the SpincastGsonPlugin
plugin :
{% verbatim %}
Spincast.configure()
.disableDefaultJsonPlugin()
.plugin(new SpincastGsonPlugin())
// ...
{% endverbatim %}
{% endblock %}