Parse JSON in Java: Jackson and Gson Guide
Java doesn't include a JSON library in the standard library, but two libraries dominate: Jackson (most widely used, default in Spring Boot) and Gson (Google's library, simpler API). Both convert JSON to Java objects and back in a few lines of code.
Use Jsonic's JSON Validator to test your JSON before parsing it in Java.
Validate JSONJackson: parse JSON to a POJO with ObjectMapper.readValue
Add the Jackson Databind dependency to your Maven pom.xml:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.0</version>
</dependency>Then use ObjectMapper.readValue() to deserialize a JSON string into a Java class:
import com.fasterxml.jackson.databind.ObjectMapper;
public class Main {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"id\":1,\"name\":\"Alice\",\"email\":\"alice@example.com\"}";
User user = mapper.readValue(json, User.class);
System.out.println(user.getName()); // Alice
}
}
// POJO (fields need getters/setters or Jackson annotations)
public class User {
private int id;
private String name;
private String email;
// getters and setters...
}ObjectMapper is thread-safe once configured — create it once and reuse it throughout your application, such as a static field or a Spring bean.
Jackson annotations
Jackson provides annotations to control how Java fields map to JSON keys during both serialization (Java to JSON) and deserialization (JSON to Java):
| Annotation | Effect | Example |
|---|---|---|
@JsonProperty("name") | Map field to a specific JSON key | @JsonProperty("user_id") private int id; |
@JsonIgnore | Exclude field from JSON entirely | @JsonIgnore private String password; |
@JsonAlias({"nm","name"}) | Accept multiple key names during deserialization | @JsonAlias({"nm"}) private String name; |
@JsonInclude(NON_NULL) | Omit null fields when serializing | Class-level annotation on the POJO |
Parse JSON arrays in Java
To deserialize a JSON array into a typed Java List, pass a TypeReference as the second argument. This is required because Java erases generic type information at runtime.
import com.fasterxml.jackson.core.type.TypeReference;
import java.util.List;
List<User> users = mapper.readValue(
"[{\"id\":1,\"name\":\"Alice\"},{\"id\":2,\"name\":\"Bob\"}]",
new TypeReference<List<User>>() {}
);
System.out.println(users.size()); // 2
System.out.println(users.get(0).getName()); // AliceThe anonymous subclass new TypeReference<List<User>>() {} captures the generic parameter at compile time, preserving it for Jackson to use at runtime.
Dynamic JSON with JsonNode
When you don't have a POJO and need to navigate an unknown JSON structure, use mapper.readTree() to get a JsonNode tree:
import com.fasterxml.jackson.databind.JsonNode;
JsonNode root = mapper.readTree(json);
// Read fields
String name = root.get("name").asText();
int id = root.get("id").asInt();
// Check existence before reading
if (root.has("email")) {
String email = root.get("email").asText();
}
// Traverse nested objects safely
JsonNode city = root.path("address").path("city");
String cityName = city.isMissingNode() ? "unknown" : city.asText();path() never returns null — it returns a MissingNode when a key is absent, which is safer than get() which returns null for missing keys.
Serialize a Java object to JSON
ObjectMapper writes Java objects to JSON strings or files with a single method call:
User user = new User(1, "Alice", "alice@example.com");
// Compact JSON string
String compact = mapper.writeValueAsString(user);
// {"id":1,"name":"Alice","email":"alice@example.com"}
// Pretty-printed JSON string
String pretty = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(user);
// {
// "id" : 1,
// "name" : "Alice",
// "email" : "alice@example.com"
// }
// Write directly to a file
mapper.writeValue(new File("output.json"), user);writeValueAsString() returns a String; writeValue() with a File writes directly to disk without building an intermediate string in memory.
Gson: parse JSON (alternative to Jackson)
Google's Gson library provides a simpler API with no setup required beyond adding the dependency. Add it to your Gradle build:
implementation 'com.google.code.gson:gson:2.10.1'Then use the Gson class directly:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
Gson gson = new Gson();
// Deserialize JSON string to POJO
User user = gson.fromJson(json, User.class);
System.out.println(user.getName()); // Alice
// Serialize POJO to JSON string
String output = gson.toJson(user);
// Pretty-printed output
Gson prettyGson = new GsonBuilder().setPrettyPrinting().create();
String pretty = prettyGson.toJson(user);Gson accesses fields directly — it doesn't require getters or setters. For simple data classes with no special mapping needs, Gson works with zero annotations.
Jackson vs Gson: comparison
Both libraries handle the same use cases, but they differ in defaults, API style, and ecosystem integration:
| Feature | Jackson | Gson |
|---|---|---|
| Default in Spring Boot | Yes | No |
| Performance | Faster for large payloads | Slightly slower |
| Dynamic navigation | JsonNode API | JsonElement / JsonObject |
| Field rename annotation | @JsonProperty | @SerializedName |
| Ignore field annotation | @JsonIgnore | @Expose (opt-in mode) |
| Null handling | Configurable (omit or include) | Serializes nulls by default |
| Streaming API | Yes (JsonParser) | Yes (JsonReader) |
| Requires getters/setters | By default, yes | No (uses fields directly) |
Jackson is the better default for new projects, especially if you're using Spring Boot. Gson is a good fit for Android development and small utilities where its simpler API is an advantage.
Frequently asked questions
Do I need getters and setters for Jackson to work?
By default, Jackson uses getter and setter methods to access fields. You can switch to field-level access by calling mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY) on your ObjectMapper, or annotate individual fields with @JsonProperty to force field access for those fields specifically.
How do I handle a JSON field that might be null in Java?
Declare the Java field as the wrapper type (Integer instead of int, String instead of a primitive). Both Jackson and Gson set null JSON fields to null in the Java object automatically. Always check for null before using the value to avoid NullPointerException.
What is the difference between readValue and readTree in Jackson?
readValue maps JSON to a typed POJO class and throws if the structure doesn't match. readTree returns a JsonNode tree you can navigate dynamically — no POJO required. Use readValue for known, stable JSON structures and readTree when the shape of the JSON is unknown or varies at runtime.
How do I parse a JSON file in Java with Jackson?
Use mapper.readValue(new File("data.json"), User.class) to parse a JSON file into a POJO directly. For large JSON array files, use mapper.readerFor(User.class).readValues(new File("data.json")) to get a MappingIterator that streams records one at a time without loading the whole file into memory.
Can I rename a JSON field without changing the Java field name?
Yes. With Jackson, add @JsonProperty("json_key_name") on the Java field. With Gson, add @SerializedName("json_key_name"). Both annotations map the Java field to a different name in the serialized JSON without renaming the Java field itself.
Is ObjectMapper thread-safe in Jackson?
Yes, once configured. Create a single ObjectMapper instance — typically as a static field or a Spring bean — and reuse it across all threads. Avoid reconfiguring it after first use. For per-call configuration, use ObjectReader and ObjectWriter, which are immutable and safe to create on every request.
Format and validate JSON
Before parsing JSON in Java, paste it into Jsonic's JSON Formatter to catch syntax errors, inspect the structure, and pretty-print nested objects — saving you from cryptic JsonParseException messages at runtime.