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!
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.
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* }
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.
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:
{ "name": "BLUE", "label": "The color blue" }
InstantSerializer
This serializes Instant
objects by calling their .toString() method.
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>2.2.0</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()) // ...