Skip to content

Commit

Permalink
Add Gson and Jackson
Browse files Browse the repository at this point in the history
  • Loading branch information
T5750 committed Feb 14, 2020
1 parent a731731 commit 10b86d6
Show file tree
Hide file tree
Showing 28 changed files with 1,093 additions and 4 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
## What's included
A ~ C | D ~ G | H ~ L | M ~ P | Q ~ S | T ~ Z
----|----|----|----|----|----
| [ASM](jdk8/README.md) | | [Javassist](jdk8/README.md) | [nio](nio/README.md) | [security](security/README.md) | [threads](threads/README.md)
| [ASM](jdk8/README.md) | [Gson](utils/README.md) | [Javassist](jdk8/README.md) | [nio](nio/README.md) | [security](security/README.md) | [threads](threads/README.md)
| [blockchain](blockchain/README.md) | | [jdk7](jdk7/README.md) | [patterns](patterns/README.md) | | [utils](utils/README.md)
| | | [jdk8](jdk8/README.md) | | |
| | | [jvm](jvm/README.md) | | |
Expand Down
3 changes: 2 additions & 1 deletion doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ Java Repositories
nio/index
patterns/index
security/index
threads/index
threads/index
utils/index
27 changes: 27 additions & 0 deletions doc/source/utils/gson/convertJsonToMap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Convert JSON to a Map

## Passing Map.class
In general, Gson provides the following API in its `Gson` class to convert a JSON string to an object:
```
public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException;
```
- `classOfT`: is the class of the object which we intend the JSON to parse into.
- If there are duplicate keys, though, coercion will fail and it will throw a `JsonSyntaxException`.

## Using TypeToken
To overcome the problem of [type-erasure](https://www.baeldung.com/java-type-erasure) for the generic types, `Gson` has an overloaded version of the API:
```
public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException;
```

We can construct a `Map` with its type parameters using Gson's `TypeToken`. The `TypeToken` class returns an instance of `ParameterizedTypeImpl` that preserves the type of the key and value even at runtime

## Using Custom JsonDeserializer
When we need fine-grained control over the construction of our `Map` object, we can implement a custom deserializer of type `JsonDeserializer<Map>`.
- `StringDateMapDeserializer`

## Results
- `ConvertJsonToMapTest`

## References
- [Convert JSON to a Map Using Gson](https://www.baeldung.com/gson-json-to-map)
23 changes: 23 additions & 0 deletions doc/source/utils/gson/convertStringToJsonObject.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Convert String to JsonObject

## Using JsonParser
The first approach we'll see for converting a JSON `String` to a `JsonObject` is a two-step process that uses the `JsonParser` class.
1. we need to parse our original `String`.
2. Once we have our `String` parsed in a `JsonElement` tree, we'll use the `getAsJsonObject()` method, which will return the desired result.

Gson provides us a parser called `JsonParser`, which parses the specified JSON `String` into a parse tree of `JsonElements`:
```
public JsonElement parse(String json) throws JsonSyntaxException
```

## Using fromJson
In our second approach, we'll see how to create a `Gson` instance and use the `fromJson` method. This method deserializes the specified JSON `String` into an object of the specified class:
```
public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException
```

## Results
- `ConvertStringToJsonObjectTest`

## References
- [Convert String to JsonObject with Gson](https://www.baeldung.com/gson-string-to-jsonobject)
37 changes: 37 additions & 0 deletions doc/source/utils/gson/gson.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Gson

Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Gson can work with arbitrary Java objects including pre-existing objects that you do not have source-code of.

There are a few open-source projects that can convert Java objects to JSON. However, most of them require that you place Java annotations in your classes; something that you can not do if you do not have access to the source-code. Most also do not fully support the use of Java Generics. Gson considers both of these as very important design goals.

## Goals
Provide simple `toJson()` and `fromJson()` methods to convert Java objects to JSON and vice-versa
Allow pre-existing unmodifiable objects to be converted to and from JSON
Extensive support of Java Generics
Allow custom representations for objects
Support arbitrarily complex objects (with deep inheritance hierarchies and extensive use of generic types)

## Download
Gradle:
```
dependencies {
implementation 'com.google.code.gson:gson:2.8.6'
}
```
Maven:
```
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
```

## Documentation
- [API Javadoc](https://www.javadoc.io/doc/com.google.code.gson/gson): Documentation for the current release
- [User guide](https://github.com/google/gson/blob/master/UserGuide.md): This guide contains examples on how to use Gson in your code.
- [Change log](https://github.com/google/gson/blob/master/CHANGELOG.md): Changes in the recent versions
- [Design document](https://github.com/google/gson/blob/master/GsonDesignDocument.md): This document discusses issues we faced while designing Gson. It also includes a comparison of Gson with other Java libraries that can be used for Json conversion

## References
- [Gson](https://github.com/google/gson)
82 changes: 82 additions & 0 deletions doc/source/utils/gson/gsonJackson.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Gson vs Jackson

## Gson Serialization
### Simple Serialization
By default:
- All properties are serialized because they have no `null` values
- `dateOfBirth` field was translated with the default Gson date pattern
- Output is not formatted and JSON property names correspond to the Java entities

### Custom Serialization
Using a custom serializer allows us to modify the standard behavior. We can introduce an output formatter with HTML, handle `null` values, exclude properties from output, or add a new output.
- `ActorGsonSerializer`

In order to exclude the `director` property, the `@Expose` annotation is used for properties we want to consider:
```
public class MovieWithNullValue {
@Expose
private String imdbId;
private String director;
@Expose
private List<ActorGson> actors;
}
```

Notice that:
- the output is formatted
- some property names are changed and contain HTML
- `null` values are included, and the `director` field is omitted
- `Date` is now in the `dd-MM-yyyy` format
- a new property is present – `N° Film`
- filmography is a formatted property, not the default JSON list

## Gson Deserialization
### Simple Deserialization
As was the case with the simple serializer:
- the JSON input names must correspond with the Java entity names, or they are set to `null`.
- `dateOfBirth` field was translated with the default Gson date pattern, ignoring the time zone.

### Custom Deserialization
Using a custom deserializer allows us to modify the standard deserializer behavior.
- `ActorGsonDeserializer`

## Jackson Serialization
### Simple Serialization
Some notes of interest:
- `ObjectMapper` is our Jackson serializer/deserializer
- The output JSON is not formatted
- By default, Java Date is translated to `long` value

### Custom Serialization
We can create a Jackson serializer for `ActorJackson` element generation by extending `StdSerializer` for our entity. Again note that the entity getters/setters must be `public`

## Jackson Deserialization
### Simple Deserialization
As was the case with the simple serializer:
- the JSON input names must correspond with the Java entity names, or they are set to `null`,
- `dateOfBirth` field was translated with the default Jackson date pattern, ignoring the time zone.

### Custom Deserialization
Using a custom deserializer allows us to modify the standard deserializer behavior.

Alternatively, we could have created a custom deserializer for the `ActorJackson` class, registered this module with our `ObjectMapper`, and deserialized the date using the `@JsonDeserialize` annotation on the `ActorJackson` entity.

The disadvantage of that approach is the need to modify the entity, which may not be ideal for cases when we don't have access to the input entity classes.

## Conclusion
Both Gson and Jackson are good options for serializing/deserializing JSON data, simple to use and well documented.

Advantages of Gson:
- Simplicity of `toJson`/`fromJson` in the simple cases
- For deserialization, do not need access to the Java entities

Advantages of Jackson:
- Built into all JAX-RS (Jersey, Apache CXF, RESTEasy, Restlet), and Spring framework
- Extensive annotation support

## Results
- `GsonJacksonTest`
- `JacksonGsonTest`

## References
- [Jackson vs Gson](https://www.baeldung.com/jackson-vs-gson)
12 changes: 12 additions & 0 deletions doc/source/utils/gson/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Gson
===============================

.. toctree::
:maxdepth: 3
:numbered: 0

gson
convertJsonToMap
convertStringToJsonObject
saveJsonFile
gsonJackson
57 changes: 57 additions & 0 deletions doc/source/utils/gson/saveJsonFile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Save Data to a JSON File

## Saving Data to a JSON File
We'll use the `toJson(Object src, Appendable writer)` method from the `Gson` class to convert a Java data type into JSON and store it in a file. The `Gson()` constructor creates a `Gson` object with default configuration:
```
Gson gson = new Gson();
```
Now, we can call `toJson()` to convert and store Java objects.

### Primitives
Saving primitives to a JSON file is pretty straight-forward using GSON:
```
gson.toJson(123.45, new FileWriter(filePath));
```

### Custom Objects
```
public class User {
private int id;
private String name;
private transient String nationality;
}
```
If a field is marked `transient`, it's ignored by default and not included in the JSON serialization or deserialization. As a result, the `nationality` field isn't present in the JSON output.

Also by default, Gson omits `null` fields during serialization. So if we consider this example:
```
gson.toJson(new User(1, null, "Unknown"), new FileWriter(filePath));
```
the file output will be:
```
{"id":1}
```

### Collections
We can store a collection of objects in a similar manner:
```
User[] users = new User[] { new User(1, "Mike"), new User(2, "Tom") };
gson.toJson(users, new FileWriter(filePath));
```

## Using GsonBuilder
In order to tweak the default Gson configuration settings, we can utilize the `GsonBuilder` class.

This class follows the builder pattern, and it's typically used by first invoking various configuration methods to set desired options, and finally calling the `create()` method:
```
Gson gson = new GsonBuilder()
.setPrettyPrinting()
.create();
```
Here, we're setting the pretty print option which is by default set to `false`. Similarly, to include `null` values in serialization, we can call `serializeNulls()`.

## Results
- `SaveJsonFileTest`

## References
- [Save Data to a JSON File with Gson](https://www.baeldung.com/gson-save-file)
8 changes: 8 additions & 0 deletions doc/source/utils/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Utils
===============================

.. toctree::
:maxdepth: 3
:numbered: 0

gson/index
16 changes: 14 additions & 2 deletions utils/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# utils
# Utils

## Contents
- [hyperic-sigar](hyperic-sigar/README.md)
- [zip](zip/README.md)
- [zip](zip/README.md)

### Gson
- [Gson](../doc/source/utils/gson/gson.md)
- [Convert JSON to a Map](../doc/source/utils/gson/convertJsonToMap.md)
- [Convert String to JsonObject](../doc/source/utils/gson/convertStringToJsonObject.md)
- [Save Data to a JSON File](../doc/source/utils/gson/saveJsonFile.md)
- [Gson vs Jackson](../doc/source/utils/gson/gsonJackson.md)

## Runtime Environment
- [Java 8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
- [Gson 2.8.5](https://github.com/google/gson)
- [Jackson 2.x](https://github.com/FasterXML/jackson)
42 changes: 42 additions & 0 deletions utils/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,47 @@
<module>zip</module>
</modules>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<gson.version>2.8.5</gson.version>
<jackson.version>2.9.7</jackson.version>
<junit.version>4.11</junit.version>
</properties>

<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
48 changes: 48 additions & 0 deletions utils/src/main/java/t5750/utils/entity/Movie.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package t5750.utils.entity;

import java.util.List;

public class Movie {
private String imdbId;
private String director;
private List actors;

public Movie(String imdbId, String director, List actors) {
this.imdbId = imdbId;
this.director = director;
this.actors = actors;
}

public Movie() {
}

public String getImdbId() {
return imdbId;
}

public void setImdbId(String imdbId) {
this.imdbId = imdbId;
}

public String getDirector() {
return director;
}

public void setDirector(String director) {
this.director = director;
}

public List getActors() {
return actors;
}

public void setActors(List actors) {
this.actors = actors;
}

@Override
public String toString() {
return "Movie [imdbId=" + imdbId + ", director=" + director + ",actors="
+ actors + "]";
}
}

0 comments on commit 10b86d6

Please sign in to comment.