Introduction
The JSON format is one of the most popular ways to serialize data. Knowing how to read and write it is an important skill for any programmer. There are a couple of Java libraries that can parse JSON, but in this tutorial, we'll focus on an open-source project developed by Google called GSON.
GSON is a lightweight Java library that provides serialization/deserialization functionality. What makes GSON stand apart is its support for Generic Types, which is limited with some, but not all, alternative libraries.
Note: If you're not familiar with Generics and why this is a big deal - feel free to read our Guide to Understanding Java Generics.
Since we're working with an external library, let's add the dependency. If you're using Maven, you can add it with:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${version}</version>
</dependency>
Or if you're using Gradle, you can add:
compile group: 'com.google.code.gson', name: 'gson', version: ${version}
Creating a Custom Class
Let's create a custom class that we'll first serialize into JSON, and into which we'll deserialize from JSON - Student
:
public class Student {
private String firstName;
private String lastName;
private int studentID;
private String email;
private List<String> courses;
private FINANCE_TYPE financeType;
// Getters, setters, constructor, toString()
}
For our Student
, we additionally have an enum representing whether they're on the budget (SUBSIDIZED
) or not (UNSUBSIDIZED
):
public enum FINANCE_TYPE {
SUBSIDIZED, UNSUBSIDIZED
}
Convert Java Object to JSON Object with GSON
Now that we have defined our class, let's make an instance of it and serialize it into its equivalent JSON representation. We will do this by using the method called toJson()
that takes an object as an argument and returns the JSON representation of that object:
// Defining courses
List<String> physicsCourses = Arrays.asList("Physics 8.01", "Physics 8.012");
List<String> musicCourses = Arrays.asList("Jazz", "Blues");
// Instantiating students
Student max = new Student("Max", "Tegmark", 1254, "[email protected]", physicsCourses, FINANCE_TYPE.SUBSIDIZED);
Student amy = new Student("Amy", "Winehouse", 1328, "[email protected]", musicCourses, FINANCE_TYPE.SUBSIDIZED);
// Instantiating Gson
Gson gson = new Gson();
// Converting POJO to JSON
String maxJson = gson.toJson(max);
String amyJson = gson.toJson(amy);
System.out.println(maxJson);
System.out.println(amyJson);
This converts our POJOs to JSON Strings, which when printed result in:
{"firstName":"Max","lastName":"Tegmark","studentID":1254,"email":"[email protected]","courses":["Physics 8.01","Physics 8.012"],"financeType":"SUBSIDIZED"}
{"firstName":"Amy","lastName":"Winehouse","studentID":1328,"email":"[email protected]","courses":["Jazz","Blues"],"financeType":"SUBSIDIZED"}
Convert JSON String to Java Object
To reverse this process, and to map a JSON object to a POJO, we'll utilize the fromJson()
method. It accepts a JSON String or a Reader
and a class or a TypeToken
.
Let's first take a look at the former:
String maxJson = "{\"firstName\":\"Max\",\"lastName\":\"Tegmark\",\"studentID\":1254,\"email\":\"[email protected]\",\"courses\":[\"Physics 8.01\",\"Physics 8.012\"],\"financeType\":\"SUBSIDIZED\"}";
Gson gson = new Gson();
Student max = gson.fromJson(maxJson, Student.class);
System.out.println(max);
This instantiates and populated the max
object with the data from the JSON object:
Student{firstName='Max', lastName='Tegmark', studentID=1254, email='[email protected]', courses=[Physics 8.01, Physics 8.012], financeType=SUBSIDIZED}
Convert JSON File to Java Object
Now, we might not be working with JSON in String format - we oftentimes have to read JSON files. The fromJson()
method accepts a Reader
instance, which we can also use to provide JSON data.
Let's move Amy's data into an amy.json
file:
{
"firstName":"Amy",
"lastName":"Winehouse",
"studentID":1328,
"email":"[email protected]",
"courses":[
"Jazz",
"Blues"
],
"financeType":"SUBSIDIZED"
}
Now, we can use a Reader
, such as FileReader
to read this file and use that for the input instead of a String. Additionally, instead of using Student.class
, we provide a Type
. This Type
is extracted from Gson's TypeToken
, which is much analogous to Jackson's TypeReference
:
// Instantiate FileReader for amy.json
Reader input = new FileReader("./src/main/resources/amy.json");
//Instantiate Gson
Gson gson = new Gson();
// Create a Type via TypeToken for the Student class
Type type = new TypeToken<Student>(){}.getType();
// Read the `input` and cast into `type`
Student amy = gson.fromJson(input, type);
// Print result
System.out.println(amy);
Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!
This, surely enough also instantiates and populates our Student
POJO:
Student{firstName='Amy', lastName='Winehouse', studentID=1328, email='[email protected]', courses=[Jazz, Blues], financeType=SUBSIDIZED}
Compact and Pretty Printing
By default, GSON prints the JSON in a compact format, which we've been able to see previously:
{"firstName":"Max","lastName":"Tegmark","studentID":1254,"email":"[email protected]","courses":["Physics 8.01","Physics 8.012"],"financeType":"SUBSIDIZED"}
{"firstName":"Amy","lastName":"Winehouse","studentID":1328,"email":"[email protected]","courses":["Jazz","Blues"],"financeType":"SUBSIDIZED"}
There are no whitespaces between field names and their values, object fields and objects within arrays. Additionally, not a single newline is present. If copied as a String - \n
(newlines) will be present, though, this compact view is a a hassle to read.
We can turn on pretty-printing using Gson, fairly easily. When instantiating Gson
, instead of calling the default, empty constructor - we can use the GsonBuilder()
constructor:
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Now, we can use the gson
instance much the same way as we did before:
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String amyJson = gson.toJson(amy);
System.out.println(amyJson);
Though, this time around, when printed - the JSON string has pretty-printing turned on:
{
"firstName": "Amy",
"lastName": "Winehouse",
"studentID": 1328,
"email": "[email protected]",
"courses": [
"Jazz",
"Blues"
],
"financeType": "SUBSIDIZED"
}
Naming JSON Fields with @SerializedName
Serialization is commonly used to transfer data between services - most notably, through REST APIs. When dealing with different services, teams or even languages that are processing the data we're providing - we might want to change the serialized names of certain fields to conform to more widely accepted standards, or to the standards of a certain service that'll be processing the data we provide.
For example, we might be providing JSON data from a Java service to a Python service. Java naming conventions follow CamelCase, while Python's naming conventions follow lowercase_with_underscores
for non-constants and classes.
Knowing that we'll be providing our data to a service or person who might want to use different conventions, we can change the serialized names of our fields to not match the ones in our POJO, via the @SerializedName
annotation:
public class Student {
@SerializedName("first_name")
private String firstName;
@SerializedName("last_name")
private String lastName;
@SerializedName("student_id")
private int studentID;
@SerializedName("student_email")
private String email;
@SerializedName("student_courses")
private List<String> courses;
@SerializedName("student_finance_type")
private FINANCE_TYPE financeType;
// Getters, setters, constructor, toString()
}
Now, when serialized, these names will be used instead of our field names:
String amyJson = gson.toJson(amy);
System.out.println(amyJson);
Which results in:
{
"first_name": "Amy",
"last_name": "Winehouse",
"student_id": 1328,
"student_email": "[email protected]",
"student_courses": [
"Jazz",
"Blues"
],
"student_finance_type": "SUBSIDIZED"
}
This also works the other way around - if we receive JSON with first_name
and our Student
POJO has first_name
mapped to firstName
, we'll deserialize this just fine:
String input = "{\"first_name\":\"Amy\",\"last_name\":\"Winehouse\",\"student_id\":1328,\"student_email\":\"[email protected]\",\"student_courses\":[\"Jazz\",\"Blues\"],\"student_finance_type\":\"SUBSIDIZED\"}";
Gson gson = new Gson();
Student amy = gson.fromJson(input, Student.class);
System.out.println(amy);
This results in:
Student{firstName='Amy', lastName='Winehouse', studentID=1328, email='[email protected]', courses=[Jazz, Blues], financeType=SUBSIDIZED}
Conclusion
In this tutorial, we took a look at how to convert a Java Object into a JSON Object with Gson's toJson()
method, as well as how to convert a JSON Object into a Java Object with Gson's fromJson()
method.
We've also explored how to enable pretty-printing, as well as change the serialized names of fields.