Saturday, April 22, 2023

3 ways to parse JSON String to Object in Java [Jackson, Gson, and json-simple Example]

One of the common task in Java web application, particularly the ones which deals with RESTful web services are parsing JSON messages. Many times you need to parse JSON to create a Java object like parsing a JSON message to create a POJO,  for example, an Order or a Book. Representing JSON in Java is easy, it's like a String value but unfortunately, JDK doesn't provide any standard API to parse JSON in Java. There were talks to add JSON parsing API in JDK 9 but that didn't materialize, but you don't need to worry. There are many good open-source JSON parsing libraries you can use to parse any kind of JSON in your Java program. 


How to parse JSON String to Object in Java?

There are multiple ways to parse JSON String to Object in Java. This process is known as JSON Deserialization because we are converting JSON String to a Java object. In this article, I'll introduce 3 essential JSON parsing libraries: Jackson, Gson, and json-simple. I'll also explain to you how to download those libraries and how to use them to parse JSON in Java. 


1. Parsing JSON using Jackson in Java

It's pretty easy to parse JSON messages into a Java object using Jackson. You just need to use the ObjectMapper class, which provides the readValue() method. This method can convert JSON String to Java object, that's why it takes JSON as a parameter and the Class instance in which you want to parse your JSON. 

Here is an example to convert our JSON String to an EBook object in Java:

ObjectMapper mapper = new ObjectMapper();
EBook effectiveJava = mapper.readValue(JSON, EBook.class);

Also, the readValue method throws IOException. I have omitted the try-catch statement for the sake of readability but you need to either throw that exception or catch it using the try-catch-finally block. 

This is probably the single most important JSON library you should know as a Java developer. It's feature-rich and also quite fast. Usually, you don't need any other JSON library if you are using Jackson. 

Btw, to use the Jackson library, you need to use either jackson-core.jar, jackson-databind.jar, or jackson-annotations.jar in your classpath. Alternatively, you can also add the following Maven dependency in your Eclipse project's pom.xml, if you are using Maven in Eclipse:

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.2.3</version>
</dependency>



And, here is the code:

// example 1 - parsing JSON using Jackson in Java
ObjectMapper mapper = new ObjectMapper();
try {
EBook effectiveJava = mapper.readValue(JSON, EBook.class);
System.out.println("Java object after parsing JSON using Jackson");
System.out.println(effectiveJava);

} catch (IOException e) { 
e.printStackTrace();
}

That's all you need to parse a JSON message in Java using Jackson.  Now, let's see another powerful library to parse JSON in Java. 




2. Parsing JSON using Gson in Java

The Gson is my second favorite JSON parsing library. It probably provides the cleaner code to parse JSON in Java. With no checked exception to handle, you literally need to follow two lines of code to parse your JSON into a Java object. 

Here I am converting our JSON message into an EBook object:

Gson gson = new Gson(); 
EBook effectiveJava3rdEdition = gson.fromJson(JSON, EBook.class);

The code is pretty similar to the Jackson parsing code but it's much more readable. The fromJson() method takes a JSON string and the type of class you want to convert the JSON string into a Java object.

Btw, you need gson.jar in your classpath to use this library. Alternatively, you can also add the following maven dependency if you are using Maven in your project:

<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.3.1</version>
</dependency>

And, here is the complete code example you can use to parse JSON messages using the Gson library

// example 2 - parsing JSON using Gson in Java
Gson gson = new Gson(); 
EBook effectiveJava3rdEdition = gson.fromJson(JSON, EBook.class);
System.out.println("Java object after parsing JSON using Gson");
System.out.println(effectiveJava3rdEdition);

That's all you will need to parse a JSON message into Java using the Gson library.  Now let's see another, third way to parse JSON String to Java object.




3. Parsing JSON using json-simple in Java

The json-simple is a low-weight simple library that doesn't depend on any other library. If the size of JAR is your concern and you are not bothered about functionalities or features then you can use json-simple to parse JSON in Java. 

Here is an example of parsing a JSON message into a Java object. We have a class called JSONParser which is similar to ObjectMapper of Jackson but here we are parsing into JSONObject rather than a POJO, hence we need to extract each attribute one by one to create a Java object. 

JSONParser parser = new JSONParser(); 
JSONObject json = (JSONObject) parser.parse(JSON);
String title = (String) json.getOrDefault("title", "");
String author = (String) json.getOrDefault("author", "");
int price = ((Long) json.getOrDefault("price", 0)).intValue();
int year = ((Long) json.getOrDefault("year", 2018)).intValue();
int edition = ((Long) json.getOrDefault("edition", 2)).intValue();
int ratings = ((Long) json.getOrDefault("ratings", 0)).intValue();

EBook effecitveJava2ndEdition 
  = new EBook(title, author, price, year, edition, ratings);

This seems a lot of code, comparing Gson and Jackson, hence I personally prefer Jackson. 

Anyway, if you want to use the json-simple library in your project you need to include json-simple.jar into the classpath. Alternatively, you can also use the following xml snippet to download dependency using maven:

<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>

Just add this into the pom.xml of your project and Maven will do the rest. Btw, if you want to know more about JSON, see the Beginning JSON book. 


'

Java Program to Parse JSON String to Object in Java - Deserialization Example

Here is our sample example to parse a JSON String in Java using Jackson, Gson, and json-simple libraries. You can run this program as it is by copying it into your Eclipse IDE, though you need to add the required JAR files for all these 3 JSON parsing libraries. 

If you use Maven then you can also add the maven dependency in your pom.xml to run this program. Maven will then download the required JAR files from the maven central repository.

import java.io.IOException;

import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;



/*
* Java Program to iterate over JSONObject and JSONArray of Jackson API
*/
public class JacksonTest {

private static String JSON = "{\r\n" + 
" \"title\" : \"Effective Java\",\r\n" + 
" \"author\" : \"Joshua Bloch\",\r\n" + 
" \"price\" : 42,\r\n" + 
" \"year\" : 2018,\r\n" + 
" \"edition\" : 3,\r\n" + 
" \"ratings\" : 10\r\n" + 
"}";


public static void main(String args[]){

// example 1 - parsing JSON using Jackson in Java
ObjectMapper mapper = new ObjectMapper();
try {
EBook effectiveJava = mapper.readValue(JSON, EBook.class);
System.out.println("Java object after parsing JSON using Jackson");
System.out.println(effectiveJava);

} catch (IOException e) { 
e.printStackTrace();
}


// example 2 - parsing JSON using Gson in Java
Gson gson = new Gson(); 
EBook effectiveJava3rdEdition = gson.fromJson(JSON, EBook.class);
System.out.println("Java object after parsing JSON using Gson");
System.out.println(effectiveJava3rdEdition);


// example 3 - parsing JSON using JSON-Simple in Java
JSONParser parser = new JSONParser(); 
try {
JSONObject json = (JSONObject) parser.parse(JSON);
String title = (String) json.getOrDefault("title", "");
String author = (String) json.getOrDefault("author", "");
int price = ((Long) json.getOrDefault("price", 0)).intValue();
int year = ((Long) json.getOrDefault("year", 2018)).intValue();
int edition = ((Long) json.getOrDefault("edition", 2)).intValue();
int ratings = ((Long) json.getOrDefault("ratings", 0)).intValue();

EBook effecitveJava2ndEdition 
  = new EBook(title, author, price, year, edition, ratings);
System.out.println("Java object after parsing JSON using json-simple");
System.out.println(effecitveJava2ndEdition);

} catch (ParseException e) {
e.printStackTrace();
}

}

}

class EBook{
private String title;
private String author;
private int price;
private int year;
private int edition;
private int ratings;

public EBook(){
//no-arg constructor required by JSON parsing library
}

public EBook(String title, String author, int price, 
int year, int edition, int ratings) {
this.title = title;
this.author = author;
this.price = price;
this.year = year;
this.edition = edition;
this.ratings = ratings;
}

public String getTitle() {
return title;
}
public String getAuthor() {
return author;
}
public int getPrice() {
return price;
}
public int getYear() {
return year;
}
public int getEdition() {
return edition;
}
public int getRatings() {
return ratings;
}
public void setTitle(String title) {
this.title = title;
}
public void setAuthor(String author) {
this.author = author;
}
public void setPrice(int price) {
this.price = price;
}
public void setYear(int year) {
this.year = year;
}
public void setEdition(int edition) {
this.edition = edition;
}
public void setRatings(int ratings) {
this.ratings = ratings;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((author == null) ? 0 : author.hashCode());
result = prime * result + edition;
result = prime * result + price;
result = prime * result + ratings;
result = prime * result + ((title == null) ? 0 : title.hashCode());
result = prime * result + year;
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof EBook))
return false;
EBook other = (EBook) obj;
if (author == null) {
if (other.author != null)
return false;
} else if (!author.equals(other.author))
return false;
if (edition != other.edition)
return false;
if (price != other.price)
return false;
if (ratings != other.ratings)
return false;
if (title == null) {
if (other.title != null)
return false;
} else if (!title.equals(other.title))
return false;
if (year != other.year)
return false;
return true;
}

@Override
public String toString() {
return "EBook [title=" + title + ", author=" + author + ", price="
+ price + ", year=" + year + ", edition=" + edition
+ ", ratings=" + ratings + "]";
} 


}

Output:
Java object after parsing JSON using Jackson
EBook [title=Effective Java, author=Joshua Bloch, 
price=42, year=2018, edition=3, ratings=10]
Java object after parsing JSON using Gson
EBook [title=Effective Java, author=Joshua Bloch, 
price=42, year=2018, edition=3, ratings=10]
Java object after parsing JSON using json-simple
EBook [title=Effective Java, author=Joshua Bloch, 
price=42, year=2018, edition=3, ratings=10]



5. Things to remember while parsing JSON in Java

Here is a list of a couple of things you should remember while parsing JSON in Java using popular JSON parsing libraries like Jackson, Gson, and JSON-Simple:

1. Always provide a no-argument constructor in your POJO class i.e. the class you want to parse your JSON into. This no-arg or default constructor is used by the JSON parsing library to create instances of your class and without that, they can't function. Jackson will throw the following error if your POJO doesn't contain a no-argument constructor:

com.fasterxml.jackson.databind.JsonMappingException: 
No suitable constructor found for type [simple type, class EBook]: 
can not instantiate from JSON object (need to add/enable type information?)
at [Source: java.io.StringReader@5b464ce8; line: 2, column: 2]
at com.fasterxml.jackson.databind
.JsonMappingException.from(JsonMappingException.java:164)
at com.fasterxml.jackson.databind.deser
.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:984)
at com.fasterxml.jackson.databind.deser
.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:276)
at com.fasterxml.jackson.databind.deser
.BeanDeserializer.deserialize(BeanDeserializer.java:121)
at com.fasterxml.jackson.databind
.ObjectMapper._readMapAndClose(ObjectMapper.java:2888)
at com.fasterxml.jackson.databind
.ObjectMapper.readValue(ObjectMapper.java:2034)
at JacksonTest.main(JacksonTest.java:27)


2. Don't put the comma after the last element, I made the same mistake and then spend a couple of minutes trying to find and fix the problem. It usually gives the following error:

com.fasterxml.jackson.core.JsonParseException: Unexpected character ('}' 
(code 125)): was expecting double-quote to start field name
at [Source: java.io.StringReader@19dfb72a; line: 8, column: 2]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1369)
at com.fasterxml.jackson.core.base
.ParserMinimalBase._reportError(ParserMinimalBase.java:532)
at com.fasterxml.jackson.core.base
.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:453)
at com.fasterxml.jackson.core.json
.ReaderBasedJsonParser._handleUnusualFieldName(ReaderBasedJsonParser.java:1267)
at com.fasterxml.jackson.core.json
.ReaderBasedJsonParser._parseFieldName(ReaderBasedJsonParser.java:1162)
at com.fasterxml.jackson.core.json
.ReaderBasedJsonParser.nextToken(ReaderBasedJsonParser.java:602)
at com.fasterxml.jackson.databind.deser
.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:288)
at com.fasterxml.jackson.databind.deser
.BeanDeserializer.deserialize(BeanDeserializer.java:121)
at com.fasterxml.jackson.databind
.ObjectMapper._readMapAndClose(ObjectMapper.java:2888)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2034)
at JacksonTest.main(JacksonTest.java:27)


Since the error message wasn't very friendly. I mean it didn't say that you have got an extra comma after the last field, I thought to validate my JSON using an online JSON validator tool like https://jsonlint.com, which clearly pointed me to the error in my JSON and after correcting that i.e. removing the comma after the last element this error disappeared. 

3 Examples to parse JSON in Java using Jackson, Gson, and json-simple

3. When you are using the json-simple library to parse JSON in Java, make sure you cast the numeric object into long instead of int. Trying to directly store them into an integer variable will throw the following exception:

Exception in thread "main" java.lang.ClassCastException: 
java.lang.Long cannot be cast to java.lang.Integer
at JacksonTest.main(JacksonTest.java:54)

But, if you have integer fields in your class like in our EBook class price, year, edition, and ratings are all integer, then you need to call the intValue() method of the Long class converts a Long value to int in Java

That's all about how to parse JSON in Java. In this article, you have learned 3 ways to parse JSON String in Java using popular libraries like Jackson, Gson, and json-simple. Though you can use any of these libraries to parse your JSON, I strongly recommend you to use Jackson because it is the most popular library but also its performance is better than Gson and json-simple for most cases.

No comments :

Post a Comment