1. Introduction
When working with APIs or configuration files, JSON is often the preferred data exchange format. In Java, the org.json library provides a simple way to parse and handle JSON data. Converting JSON to Java POJOs is important because it enables us to work with typed objects instead of raw text or maps, improving readability, maintainability, and validation.
In this tutorial, we’ll see how to convert a JSONObject into a Java POJO. We use a simple example to understand the process, including converting JSON strings, handling nested objects, and verifying the mapped result.
2. Project Setup
Before starting, let’s include the org.json library in the project to parse and handle JSON data conveniently:
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20231013</version>
</dependency>
This library provides the JSONObject and JSONArray classes that make it easier to create, read, and manipulate JSON in Java.
3. Define the POJO Class
Next, we define a simple User class to represent the structure of the JSON data. This class serves as the target object that the JSON is mapped into:
class User {
private String name;
private int age;
private String email;
private Address address;
// Getters and setters
}
class Address {
private String city;
private String postalCode;
// Getters and setters
}
These classes mirror the structure of the JSON data, making it straightforward to convert between JSON and Java objects.
4. Create a Sample JSONObject
Now, we create a sample string and convert it into a JSONObject.
Let’s assume the example JSON string simulates a typical scenario where an application receives JSON data from an API or configuration file:
String jsonString = """
{
"name": "Alice",
"age": 25,
"email": "[email protected]",
"address": {
"city": "Singapore",
"postalCode": "123456"
}
}
""";
JSONObject jsonObject = new JSONObject(jsonString);
Thus, the JSON includes a nested address object, reflecting a realistic JSON structure.
With the User POJO and a JSONObject prepared, several ways exist to convert this JSON data into a Java object, either manually or through libraries such as Jackson.
5. Using Manual Mapping
Manual mapping involves extracting each value from the JSONObject and setting it in the corresponding fields in the POJO.
To that end, let’s create a method to map the JSONObject to a POJO manually:
public static User mapManually(JSONObject jsonObject) {
User user = new User();
user.setName(jsonObject.getString("name"));
user.setAge(jsonObject.getInt("age"));
user.setEmail(jsonObject.getString("email"));
JSONObject addressObject = jsonObject.getJSONObject("address");
Address address = new Address();
address.setCity(addressObject.getString("city"));
address.setPostalCode(addressObject.getString("postalCode"));
user.setAddress(address);
return user;
}
This approach is clear and fairly easy to follow. It usually works well when the JSON structure is small and stable. Each field is explicitly mapped, enabling custom handling, such as default values or transformations.
Still, the manual mapping provably contains the correct values, as we can see from the test:
User user = mapManually(jsonObject);
assertEquals("Alice", user.getName());
assertEquals(25, user.getAge());
assertEquals("[email protected]", user.getEmail());
assertEquals("Singapore", user.getAddress().getCity());
assertEquals("123456", user.getAddress().getPostalCode());
However, manual mapping becomes repetitive and error-prone with large or deeply nested JSON structures.
6. Using Jackson
Jackson is a popular library that can automatically map JSON strings to POJOs.
6.1. Basics
To use Jackson, we add the respective pom.xml dependency:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.0</version>
</dependency>
After converting the JSONObject into a JSON string, Jackson handles the mapping with a single method call:
public static User mapWithJackson(JSONObject jsonObject) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readValue(jsonObject.toString(), User.class);
} catch (Exception e) {
return null;
}
}
Jackson eliminates most of the boilerplate code required for manual mapping and automatically manages complex JSON structures. It also maps nested objects, such as the address field, when the POJO structure matches the JSON hierarchy.
6.2. Collections
Collections such as lists and arrays are supported without additional setup. For instance, let’s assume the JSON includes an array of phone numbers:
{
"name": "Alice",
"age": 25,
"email": "[email protected]",
"address": {
"city": "Singapore",
"postalCode": "123456"
},
"phones": ["12345678", "87654321"]
}
A corresponding List<String> field can be added in the User class:
private List<String> phones;
Jackson maps the phones array into a Java List automatically. This suits APIs where JSON data frequently contains nested objects and arrays.
6.3. Customization
In addition, Jackson also supports customization through annotations. For example, if a JSON field name differs from the Java property, the @JsonProperty annotation can define the mapping:
class User {
@JsonProperty("full_name")
private String name;
private int age;
private String email;
// Getters and setters
}
Jackson reads the full_name field from JSON and assigns it to the name property automatically. This flexibility is useful when integrating with APIs that use different naming conventions.
Jackson also supports polymorphic deserialization, enabling it to handle JSON that represents multiple subtypes of a base class. For example, consider a base class Animal and two subclasses, Dog and Cat:
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type"
)
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Cat.class, name = "cat")
})
abstract class Animal {
private String name;
// Getter and setter
}
class Dog extends Animal {
private int barkVolume;
// Getter and setter
}
class Cat extends Animal {
private boolean likesFish;
// Getter and setter
}
With this setup, Jackson automatically determines which subclass to instantiate based on the type field in the JSON:
[
{ "type": "dog", "name": "Buddy", "barkVolume": 5 },
{ "type": "cat", "name": "Mimi", "likesFish": true }
]
The JSON can be mapped into the correct subclasses using Jackson’s ObjectMapper:
ObjectMapper mapper = new ObjectMapper();
List<Animal> animals = Arrays.asList(
mapper.readValue(jsonArrayString, Animal[].class)
);
Jackson creates a Dog object for the first entry and a Cat object for the second without extra logic.
6.4. Verification
We can verify that the Jackson mapping works correctly:
User user = mapWithJackson(jsonObject);
assertEquals("Alice", user.getName());
assertEquals("Singapore", user.getAddress().getCity());
assertEquals("123456", user.getAddress().getPostalCode());
assertEquals(2, user.getPhones().size());
assertEquals("12345678", user.getPhones().get(0));
assertEquals("87654321", user.getPhones().get(1));
The assertions validate the mapping.
7. Using Gson
Gson is another popular library for mapping JSON to Java objects. Before using it, we need to add the Gson dependency in the pom.xml:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
Gson parses the JSON string and fills the fields of the POJO, including nested objects and collections, without extra configuration.
So, we can create a simple method to map the JSONObject to the User class:
public static User mapWithGson(JSONObject jsonObject) {
Gson gson = new Gson();
return gson.fromJson(jsonObject.toString(), User.class);
}
We verify that the Gson mapping works correctly using assertions:
User user = mapWithGson(jsonObject);
assertEquals("Alice", user.getName());
assertEquals(25, user.getAge());
assertEquals("Singapore", user.getAddress().getCity());
assertEquals(2, user.getPhones().size());
Gson is lightweight and easy to use for quick conversions or small applications. It’s great when we need simple JSON-to-POJO mapping without extra configuration.
8. Conclusion
In this article, we explored several approaches to convert a JSONObject into a Java POJO using manual mapping, Jackson, and Gson. Manual mapping provides full control and suits simple JSON structures, while Jackson offers a powerful and flexible option with annotation support and polymorphic handling. Gson delivers simplicity for lightweight use cases.
As always, the source code is available over on GitHub.