Jackson and Gson are Java libraries that convert Java objects to/from JSON strings
Jackson uses streaming parsing (ObjectMapper) — faster for large payloads
Gson uses tree model (JsonParser) — simpler for small to medium data
Performance: Jackson ~30% faster on heavy payloads, Gson uses less memory (~20%)
In production, mismatched annotations between libraries silently silences null fields
Biggest mistake: forgetting a no-arg constructor breaks deserialization silently
✦ Definition~90s read
What is Working with JSON in Java?
JSON (JavaScript Object Notation) is a lightweight data-interchange format. In Java, libraries like Jackson and Gson translate between Java objects and JSON strings. This translation is called serialization (object → JSON) and deserialization (JSON → object).
★
Imagine you run a restaurant and you need to send your daily menu to five different delivery apps.
Without these libraries, you'd manually parse string buffers, handle escaping, and manage type conversions — which is error-prone and tedious. The key insight: both libraries rely on reflection, field naming conventions, and type information to map object fields to JSON keys.
Misunderstand these basics and you'll waste hours debugging silent output changes.
Plain-English First
Imagine you run a restaurant and you need to send your daily menu to five different delivery apps. Instead of calling each app and describing every dish out loud, you write it all down on a standard order form they all understand. JSON is that standard form — a universal way to package data so any app, in any language, can read it. In Java, libraries like Jackson and Gson are the printers and readers of those forms.
Every modern Java application talks to something — a REST API, a mobile client, a microservice, a database cache. And the language they almost all speak is JSON. If your Java code can't fluently read and write JSON, it's essentially mute on the modern web. This isn't a niche skill; it's table stakes for any backend role.
The problem is that Java objects and JSON text are fundamentally different things. A Java object lives in memory with types, references, and methods. JSON is just a flat string of characters. Bridging that gap — turning an object into JSON (serialization) and turning JSON back into an object (deserialization) — is exactly what libraries like Jackson and Gson were built to solve. Without them, you'd be manually parsing curly braces and handling edge cases forever.
By the end of this article you'll know how to pick the right library for your project, serialize and deserialize simple and nested Java objects, handle real-world messiness like missing fields and custom date formats, and avoid the three mistakes that show up in almost every code review involving JSON. You'll walk away ready to wire up a REST client or build an API endpoint without reaching for Stack Overflow.
What is Working with JSON in Java?
JSON (JavaScript Object Notation) is a lightweight data-interchange format. In Java, libraries like Jackson and Gson translate between Java objects and JSON strings. This translation is called serialization (object → JSON) and deserialization (JSON → object). Without these libraries, you'd manually parse string buffers, handle escaping, and manage type conversions — which is error-prone and tedious. The key insight: both libraries rely on reflection, field naming conventions, and type information to map object fields to JSON keys. Misunderstand these basics and you'll waste hours debugging silent output changes.
Type this code yourself rather than copy-pasting. The muscle memory of writing it will help it stick.
Production Insight
Real JSON parsing is never this simple.
In production, you'll deal with missing fields, null handling, and polymorphic types.
Always configure your ObjectMapper/GsonBuilder early — don't rely on defaults.
Key Takeaway
JSON bridges your Java objects to the outside world.
Mastering serialization/deserialization is non-negotiable for backend work.
Default behaviors differ — test your config before going live.
Deciding When to Configure Early
IfSimple POJO, no nested types, fixed schema
→
UseDefault ObjectMapper/GsonBuilder works
IfAny date fields, optionals, or variant schemas
→
UseConfigure modules and null handling at startup
IfPolymorphic types or abstract classes
→
UseMust configure type info / adapters upfront
thecodeforge.io
Json Java
Jackson vs Gson: When to Use Which
Jackson and Gson are the two dominant JSON libraries in the Java ecosystem. Jackson is the de facto standard for Spring Boot and other enterprise frameworks. It's annotation-driven, deeply customisable, and performs well on large payloads thanks to its streaming parser. Gson, from Google, is simpler to set up (no ObjectMapper configuration needed) and uses less memory — but it lacks Jackson's advanced features like polymorphic deserialization and tree-model modification. Jackson is the default in Spring Boot, but Gson is a solid choice for microservices or Android where simplicity and memory footprint matter more than raw speed. However, here's the real trade-off: Jackson's streaming parser keeps memory constant even for 500 MB payloads; Gson reads the entire tree into memory, which can cause OOM. Choose based on your payload profile, not just hype.
Serialization converts Java objects to JSON strings; deserialization does the reverse. Both Jackson and Gson use reflection to map field names to JSON keys by default. You can override names with @JsonProperty (Jackson) or @SerializedName (Gson). Always consider null handling: Jackson serializes nulls by default; Gson omits them unless you configure serializeNulls(). For deserialization, missing fields in JSON are simply left as null in the object — but if you have a constructor with required parameters, Jackson may fail. Use @JsonCreator to mark a constructor, or Gson's InstanceCreator for custom logic. A common pattern: create a DTO with @JsonProperty annotations and a no-arg constructor, then validate with Bean Validation after deserialization.
SerializationExample.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package io.thecodeforge;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.time.LocalDate;
publicclassUser {
@JsonProperty("user_id")
privateString id;
@JsonFormat(pattern = "yyyy-MM-dd")
privateLocalDate birthDate;
// Jackson needs a no-arg constructor OR @JsonCreatorpublicUser() {}
// getters/setters
}
// Jackson deserialization with missing fields:String json = "{\"user_id\":\"abc\"}";
User user = mapper.readValue(json, User.class);
// birthDate is null — no error unless you add @NotNull// Gson serialization with nulls:Gson gson = newGsonBuilder().serializeNulls().create();
String json = gson.toJson(user); // includes nulls
Output
{"user_id":"abc","birthDate":null} -- Jackson includes null
{"user_id":"abc"} -- Gson without serializeNulls()
No-Arg Constructor Trap
If your class has a parameterized constructor and no default constructor, Jackson throws a JsonMappingException. Gson uses sun.misc.Unsafe internally so it can create objects without calling any constructor — but fields remain null unless the JSON includes them. Always provide a default constructor or use @JsonCreator / @ConstructorProperties.
Production Insight
In a production REST API, missing fields in JSON deserialization rarely throw errors — they just set fields to null.
This is why validation at the controller boundary is critical.
Add @NotNull or @JsonProperty(required=true) to fields you cannot afford to lose.
Key Takeaway
Always define a no-arg constructor or a custom deserializer.
Assume every JSON payload is missing fields — validate explicitly.
Null serialization defaults differ: Jackson includes, Gson excludes.
Deciding Constructor Strategy
IfClass is a DTO with many optional fields
→
UseUse no-arg constructor and setters
IfImmutable class with required fields only
→
UseUse @JsonCreator on constructor; Jackson validates presence
IfMixed (some required, some optional)
→
UseNo-arg + setters + @JsonProperty(required) on required fields
thecodeforge.io
Json Java
Handling Nested Objects and Collections
JSON frequently contains nested objects and arrays. Both Jackson and Gson handle this automatically as long as the Java class has matching nested types. For example, an order containing a list of line items. The key challenge is generic types — Jackson needs TypeReference to preserve generic information; Gson uses TypeToken. Without these, deserialization produces a List<Map> instead of List<LineItem>, leading to ClassCastException later. Jackson's ObjectMapper.convertValue() can help but it's slower. Real tip: when your JSON has arrays of objects, always use TypeToken or TypeReference. Don't rely on the compiler's type inference — it won't save you at runtime.
NestedObjects.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package io.thecodeforge;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.gson.reflect.TypeToken;
// Jackson with generic listList<LineItem> items = mapper.readValue(jsonArray,
newTypeReference<List<LineItem>>() {});
// Gson with generic listList<LineItem> items = gson.fromJson(jsonArray,
newTypeToken<List<LineItem>>(){}.getType());
// Bad: loses generic typeList items = gson.fromJson(jsonArray, List.class);
// items.get(0) returns LinkedTreeMap, not LineItem — ClassCastException at runtime
Output
The bad approach compiles fine but throws ClassCastException when you access items.get(0).getName()
TypeToken & TypeReference Are Not Optional
If your JSON is an array of objects or a map with complex values, always use TypeToken (Gson) or TypeReference (Jackson). Without them, the type erasure leaves you with raw types, and runtime casts fail unpredictably.
Production Insight
I've debugged a production incident where a service returned 500s intermittently — root cause was a developer used List.class instead of TypeReference.
The error only surfaced when a particular payload triggered the getter that cast the element.
This is the kind of bug that slips past QA because the app works fine with simple payloads.
Key Takeaway
Always parameterize generic types during deserialization.
Jackson: TypeReference. Gson: TypeToken.
Incorrect generic handling is a silent time bomb.
Handling Nested Types in JSON
IfJSON has a simple object (no generics)
→
UseUse Class<T> directly
IfJSON has a List, Map, or other parameterized type
→
UseUse TypeReference (Jackson) or TypeToken (Gson)
IfYou're mapping to a known object but nested generics exist
→
UseStill use TypeReference/TypeToken — safe habit
Custom Serialization: Dates, Nulls, and Polymorphism
Real-world JSON often requires custom handling: date formats, null behaviour, and polymorphic types (e.g., a List<Animal> where each element could be Dog or Cat). Jackson provides @JsonTypeInfo and @JsonSubTypes for polymorphic deserialization. Gson requires a RuntimeTypeAdapterFactory (a third-party extension or manual implementation). Date formatting is another common issue — both libraries default to timestamps or ISO formats. Configure explicitly to match your API contract (e.g., "2026-04-22T15:30:00Z"). For null handling in collections, Jackson can omit null entries via @JsonInclude(Include.NON_NULL). A production pattern: write a custom serializer for any type that changes version often — this gives you control over backward compatibility.
The JSON must include a discriminator field (e.g., "type") to tell the deserializer which subclass to use
Jackson's @JsonTypeInfo lets you choose where the discriminator lives (property, wrapper, etc.)
Gson lacks built-in polymorphic support — use RuntimeTypeAdapterFactory or write a custom deserializer
If you don't configure polymorphism, deserialization of an abstract type fails with an error
Production Insight
Polymorphic deserialization is the #1 cause of JSON parsing failures in large codebases.
If you add a new subclass and forget to register it, the old code silently fails at runtime.
I've seen systems where a new payment method type caused 500s because the base class wasn't updated.
Key Takeaway
Polymorphism needs explicit configuration in both Jackson and Gson.
Date formatting must match your API contract — don't rely on defaults.
Test serialization for every subclass in your suite.
Custom Serialization Approach
IfSimple date formatting, no polymorphism
→
UseUse @JsonFormat / @SerializedName annotations
IfPolymorphic types with known subclasses
→
UseUse Jackson's @JsonTypeInfo + @JsonSubTypes
IfLegacy system migrating from XML/different schema
→
UseWrite a custom serializer/deserializer per type
Common JSON Mistakes in Production
Even experienced developers make recurring JSON mistakes. Three that appear in almost every code review: (1) Using the wrong library's annotations — e.g., Gson's @Expose on a Jackson project. (2) Forgetting to register Java 8 modules for LocalDate, Optional, etc. (3) Assuming null fields behave the same way across versions. Jackson 2.x changed its default null serialization behavior between minor versions — a fact that has burned many teams during upgrades. Another mistake: not testing serialization output changes when upgrading the library. CI should include a golden JSON file that every build compares against.
CommonMistakes.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package io.thecodeforge;
// Mistake 1: Mixing annotations
@Expose// Gson annotation — ignored by Jackson
@JsonIgnore// Jackson annotation — ignored by GsonprivateString internalId;
// Mistake 2: Missing JavaTimeModuleObjectMapper mapper = newObjectMapper();
mapper.writeValueAsString(LocalDate.now());
// Error: Java 8 date/time type not supported by default// Fix: register moduleObjectMapper mapper = newObjectMapper()
.registerModule(newJavaTimeModule());
Output
Without JavaTimeModule: com.fasterxml.jackson.databind.exc.InvalidDefinitionException
Version Compatibility Traps
Jackson 2.12 changed the default for WRITE_DATES_AS_TIMESTAMPS from true to false. If you upgrade Jackson without checking release notes, your API clients may start receiving ISO strings instead of timestamps — breaking backward compatibility. Always pin the version and test serialized output.
Production Insight
Mixing annotations between Jackson and Gson is the #1 code review finding.
It happens when a team inherits a project that started with Gson and migrated to Jackson halfway.
The annotations silently do nothing — your field serialization is out of your control.
Key Takeaway
Stick to one library consistently.
Register JavaTimeModule for date support.
Never assume default behavior stays the same across versions.
Avoiding Annotation Confusion
IfYou see @Expose, @SerializedName, @JsonIgnore in the same class
→
UseStop — pick one library and remove all annotations from the other
IfNew project, no existing JSON library
→
UseIf Spring Boot: Jackson. If standalone: Gson for simplicity.
IfMigrating from Gson to Jackson
→
UseReplace all @Expose with @JsonProperty and @JsonIgnore, then test
JSON Schema: Your API Contract That Actually Works
You've been burned before. A random field goes missing in production, some upstream service sends a string where you expected an integer, and now your JSON parser silently swallows the error while your payment pipeline implodes. Java's type system won't save you here — JSON is schemaless by design, which means you need an explicit contract.
JSON Schema is that contract. It's a declarative language that validates structure, types, ranges, and required fields before you ever deserialize. Think of it as a compiler for your JSON payloads. Paired with a library like everit-json-schema or networknt, you can enforce rules like "this field must be an ISO-8601 date" or "this array must have at least one element."
Why should you care? Because runtime schema validation catches what Jackson's @NotNull annotation misses — like a deeply nested field in a third-party response that just vanished. It's the difference between a 500 error and a graceful rejection with a clear error message. Put JSON Schema validation at your API boundary. Your future self (and your on-call rotation) will thank you.
Never assume external APIs adhere to their docs. Always validate incoming JSON against a schema at the edge — otherwise you get silent nulls or ClassCastExceptions deep in business logic.
Key Takeaway
Validate JSON payloads against a schema at the API boundary before deserializing — it's cheaper to reject early than debug a null pointer in a transaction handler.
Streaming JSON Parsing: When You Can't Fit the Whole File in Memory
Your microservice is humming along nicely until someone decides to dump a 2GB JSON export from a legacy system directly into your endpoint. Suddenly your beautiful Jackson ObjectMapper blows an OutOfMemoryError and your pod restarts. That's the moment you discover you've been holding the entire document tree in RAM.
Streaming JSON parsing — using JsonParser from Jackson or JsonReader from Gson — processes tokens one at a time. No DOM tree, no ObjectMapper, no loading the whole thing into memory. You get a stream of events: start object, field name, string value, end array. You decide what to keep and what to skip. This is how you handle multi-gigabyte files without breaking a sweat.
When do you need this? When your data source is unbounded — log dumps, IoT sensor batches, database exports. Don't reach for it on every endpoint; the boilerplate is higher. But keep JsonParser in your toolbox for the day your boss asks why a perfectly normal JSON file kills the service. And always set a read timeout on your HTTP client, or the streaming parser will hang forever on a slow upstream.
For huge files, combine streaming with a pushback pattern — read tokens until you find the object you need, process it, then skip the rest of the array. Cuts peak memory by 90%.
Key Takeaway
Use streaming JSON parsers for unbounded or large payloads; never load more data into heap than you can afford to lose in a crash.
Dependency Setup: Stop Copy-Pasting JARs
Most Java devs still grab a json-simple JAR from some blog post from 2013. Don't. You're not deploying WAR files to Tomcat 6 anymore. Use a build tool. This isn't optional — it's how you get reproducible builds, transitive dependency resolution, and a sane upgrade path.
json-simple lives at com.googlecode.json-simple:json-simple:1.1.1. Yes, the group is Google-adjacent. No, it's not actively maintained — but it's tiny, stable, and has zero dependencies. For Maven, drop it in <dependencies>. For Gradle, implementation 'com.googlecode.json-simple:json-simple:1.1.1'. That's it.
Why does this matter in production? Because when your CI pipeline fails because someone committed a raw JAR to lib/, you'll remember this. A single dependency declaration. Two lines max. Your team will thank you when they don't have to debug classpath hell at 2 AM.
Never mix json-simple with Jackson or Gson in the same project. They compete for the same serialization logic. Pick one per microservice.
Key Takeaway
Declare json-simple as a single Maven/Gradle dependency — never vendor JARs manually in production.
Key Classes in json-simple: You Only Need Three
json-simple keeps it brutally simple — three classes do everything. JSONObject is a Map under the hood. JSONArray is a List. JSONParser reads strings or streams into those types. That's the entire API. No factory abstractions, no builder patterns, no thirty-method interfaces.
Here's the flow: parse a JSON string with JSONParser.parse() — it returns an Object. Cast it to JSONObject or JSONArray. Use get(), put(), getString() — yes, it has typed getters, so you don't always need casts. Want to write JSON? new JSONObject() then put() keys, then call toString() or writeJSONString() on an output stream.
The WHY: minimal cognitive overhead. When you're debugging a production incident at 3 AM, you don't want to decode a factory pattern. You want obj.get("key") to work. json-simple delivers that, no ceremony. Use it for config files, quick API mocks, or any place where JSON size stays under a few megabytes.
Use JSONObject.toString() for debugging — it pretty-prints by default. For production logs, always call .toJSONString() to avoid escaping issues with multi-line output.
Key Takeaway
JSONObject, JSONArray, JSONParser — three classes cover 99% of json-simple usage. Know them, use them, move on.
JSONException: Why You Can't Ignore It
Every JSON library throws variants of checked or unchecked exceptions when parsing fails. The root cause is almost never 'bad JSON' — it's mismatched expectations. A field you assumed was String arrives as null, a nested object is missing entirely, or the API returns an error envelope instead of the expected payload. Catching JSONException (or JsonParseException in Jackson) without inspecting the cause hides production bugs. The fix: always log the raw JSON input alongside the exception. In json-simple, JSONParser.parse() throws ParseException with column position data — use exception.getPosition() to pinpoint the exact character where parsing broke. Never wrap these exceptions in a generic 'Invalid request' response; they contain actionable debugging info. Treat JSON parsing failures as critical logging events, not silent catch-and-continue operations.
Catching JSONException without logging the raw input hides the root cause. A syntax error from one user's payload can propagate silently across all requests if you reuse a shared parser instance.
Key Takeaway
Always log raw JSON input with the exception position — never silence parse errors.
Prerequisite: Before You Write a Single JSON Line in Java
Working with JSON in Java is deceptively simple until your first production outage. Three prerequisites matter: 1) Know your data shape — is it fixed-schema (use Jackson with DTOs) or dynamic (use json-simple JSONObject)? 2) Understand null handling — Java null serializes to JSON null, but Optional.empty() throws by default in Jackson unless you configure SerializationFeature.WRITE_DATES_AS_TIMESTAMPS appropriately. 3) Memory boundaries — a 50MB JSON file cannot be parsed with JSONParser.parse() without causing OOM errors; you need Reader-based streaming. The single most valuable prerequisite is writing a unit test with malformed input (missing commas, extra brackets, unquoted strings) before writing any production code. This forces you to decide on error handling behavior early, avoiding silent data corruption in staging.
Skipping the prerequisite test for malformed input means your exception handler is written under a 'happy path' assumption. Production JSON will break that assumption within hours.
Key Takeaway
Test malformed JSON before writing your first serialization class — error handling is the actual prerequisite.
● Production incidentPOST-MORTEMseverity: high
Silent Null Field Loss: Gson's @Expose vs Jackson's @JsonInclude
Symptom
Client apps reported missing fields in responses from the payment service. Logs showed the Java object had the fields, but the JSON output didn't contain them.
Assumption
The team assumed both libraries handled null fields identically because the object model looked the same.
Root cause
Gson's default behavior excludes null fields unless configured with GsonBuilder.serializeNulls(). Jackson had @JsonInclude(Include.ALWAYS) on the class, but Gson doesn't recognize Jackson annotations.
Fix
Add GsonBuilder().serializeNulls().create() to the Gson instance, and remove the Jackson-specific annotation. Then add a unit test that asserts null fields are present in the JSON.
Key lesson
Annotations from one library don't apply to the other — always verify default behaviors.
Never assume JSON output matches what you see in the IDE debugger.
Write contract tests that check the actual JSON string for every field, including nulls.
Production debug guideQuick symptom-to-action guide for when JSON breaks in your Java services5 entries
Symptom · 01
Deserialization throws JsonMappingException or MalformedJsonException
→
Fix
Check the JSON payload against your POJO. Use @JsonIgnoreProperties(ignoreUnknown = true) or Gson's lenient mode if the schema is loose.
Symptom · 02
Field is missing in JSON output even though POJO has it
→
Fix
Check for @JsonIgnore, @Expose(serialize = false), or null-serialization settings. Enable library-specific logging for serialization.
Symptom · 03
Date fields appear as numbers instead of strings
→
Fix
Configure date format explicitly: Jackson: ObjectMapper().registerModule(new JavaTimeModule()).disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS). Gson: new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss").create()
Symptom · 04
Circular reference causes stack overflow during serialization
→
Fix
Jackson: add @JsonManagedReference / @JsonBackReference or use @JsonIdentityInfo. Gson: use ExclusionStrategy or transient fields.
Symptom · 05
Polymorphic type fails with error 'cannot deserialize abstract type'
→
Fix
Ensure @JsonTypeInfo is configured on the base class for Jackson. For Gson, register a RuntimeTypeAdapterFactory or custom TypeAdapter.
★ JSON Debugging Cheat SheetUse these commands and techniques to diagnose JSON issues in Java services without restarting the JVM.
JSON output looks incomplete or has extra fields−
Immediate action
Dump the raw JSON string to a separate log file for inspection
Add Jackson's SerializationFeature.INDENT_OUTPUT during development to spot missing fields quickly
Deserialization fails with type mismatch+
Immediate action
Check the JSON payload's structure with a linting tool
Commands
echo '$payload' | python -m json.tool
curl -s -H 'Content-Type: application/json' -X POST -d @payload.json http://localhost:8080/api/debug/validate
Fix now
Add a fail-fast endpoint that deserializes and logs the exact error
Gson returns LinkedTreeMap instead of expected POJO+
Immediate action
Inspect the deserialization call — you likely forgot TypeToken
Commands
gson.fromJson(json, new TypeToken<List<MyPojo>>(){}.getType())
Check classpath for duplicate Gson versions
Fix now
Always use TypeToken for parameterized types; never use List.class directly
Jackson vs Gson at a Glance
Feature
Jackson
Gson
Default null serialization
Includes nulls
Excludes nulls (unless serializeNulls())
Polymorphic deserialization
Built-in (@JsonTypeInfo)
Requires external adapter
Streaming parsing
Yes (JsonParser) — memory efficient
No — tree model only
Spring Boot default
Yes (spring-boot-starter-web)
No (needs explicit dependency)
Annotation style
@JsonProperty, @JsonFormat
@SerializedName, @Expose
Configuration
ObjectMapper (global)
GsonBuilder (per instance)
Performance
Faster on large payloads (~30%)
Uses less memory (~20%)
Key takeaways
1
You now understand what Working with JSON in Java is and why it exists
2
You've seen it working in a real runnable example
3
Practice daily
the forge only works when it's hot
4
Jackson and Gson have different defaults
test serialization explicitly in every service.
5
Always provide a no-arg constructor or use @JsonCreator to avoid deserialisation failures.
6
Polymorphic types require explicit @JsonTypeInfo or a custom adapter
don't skip it.
7
Register JavaTimeModule for dates, or you'll get cryptic errors in production.
8
Never mix library annotations; pick one and stick with it.
Common mistakes to avoid
6 patterns
×
Memorising syntax before understanding the concept
Symptom
You can write Java code but don't know why a field disappears or a date format fails.
Fix
Learn the problem the library solves: mapping object fields to string keys. Practice by writing a simple POJO and inspecting the JSON output.
×
Skipping practice and only reading theory
Symptom
You understand concepts but cannot fix a failing deserialization in your project.
Fix
Create a small Java project with random JSON payloads and write both Jackson and Gson code. Break it on purpose to see the error messages.
×
Mixing Jackson and Gson annotations
Symptom
Fields with @Expose are silently ignored in Jackson projects; @JsonIgnore fields still appear in Gson output.
Fix
Choose one library and use only its annotations. If migrating, replace all annotations at once and test serialized output.
×
Forgetting to register JavaTimeModule for LocalDate
Symptom
Jackson throws InvalidDefinitionException when serializing Java 8 date/time types.
Fix
Always register new JavaTimeModule on the ObjectMapper: mapper.registerModule(new JavaTimeModule())
×
Assuming no-arg constructor is optional
Symptom
Deserialization fails with JsonMappingException when the class has a parameterized constructor only.
Fix
Always provide a no-arg constructor, or use @JsonCreator on a factory method.
×
Not testing serialized output in CI
Symptom
A library upgrade changes date format or null behaviour silently, breaking clients.
Fix
Store a golden JSON file and compare serialized output in your test suite.
INTERVIEW PREP · PRACTICE MODE
Interview Questions on This Topic
Q01SENIOR
Explain the difference between Jackson's ObjectMapper and Gson's Gson cl...
Q02SENIOR
How would you handle polymorphic deserialization with Jackson? Provide a...
Q03SENIOR
What happens if you deserialize JSON with a missing field using Jackson ...
Q04SENIOR
How do you configure Jackson to serialize dates as ISO 8601 strings inst...
Q05SENIOR
Describe a real production incident you faced with JSON serialization an...
Q01 of 05SENIOR
Explain the difference between Jackson's ObjectMapper and Gson's Gson class.
ANSWER
ObjectMapper is an immutable, configurable engine that handles both serialization and deserialization. It uses a streaming parser internally for performance. Gson is simpler — it uses reflection and a tree model. Jackson supports advanced features like polymorphic types, YAML, and XML via modules. Gson is easier to set up but less flexible. In production, Jackson is the standard for Spring Boot, Gson is common in Android and simple services.
Q02 of 05SENIOR
How would you handle polymorphic deserialization with Jackson? Provide an example.
ANSWER
Use @JsonTypeInfo and @JsonSubTypes on the base class. For example: @JsonTypeInfo(use = Id.NAME, property = "type") @JsonSubTypes({@JsonSubTypes.Type(value = Dog.class, name = "dog")}). Then when you deserialize a JSON with a "type":"dog" field, Jackson automatically creates a Dog instance. Without this, you'd get an error for abstract types. For Gson, you'd need a custom TypeAdapter or RuntimeTypeAdapterFactory.
Q03 of 05SENIOR
What happens if you deserialize JSON with a missing field using Jackson vs Gson?
ANSWER
Both Jackson and Gson leave the missing field as null in the Java object — no exception by default. However, if the field is annotated with @JsonProperty(required = true) (Jackson) or you've written a custom deserializer, you can enforce non-null values. Jackson throws a JsonMappingException only if you configure DeserializationFeature.FAIL_ON_MISSING_CREATOR_PROPERTIES. Gson does not have a built-in equivalent, so you must validate after deserialization.
Q04 of 05SENIOR
How do you configure Jackson to serialize dates as ISO 8601 strings instead of timestamps?
ANSWER
Register the JavaTimeModule and disable WRITE_DATES_AS_TIMESTAMPS: ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule()).disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS). You can also annotate specific date fields with @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'") if you need a different format per field.
Q05 of 05SENIOR
Describe a real production incident you faced with JSON serialization and how you fixed it.
ANSWER
A common one: after migrating from Gson to Jackson, null fields disappeared in the API response. We discovered Gson's default excludes nulls, while Jackson includes them. The team had not migrated the configuration. Fix: added serializeNulls() to GsonBuilder for the old endpoints and added @JsonInclude(Include.ALWAYS) for Jackson. Enforcement: added contract tests checking for null field presence.
01
Explain the difference between Jackson's ObjectMapper and Gson's Gson class.
SENIOR
02
How would you handle polymorphic deserialization with Jackson? Provide an example.
SENIOR
03
What happens if you deserialize JSON with a missing field using Jackson vs Gson?
SENIOR
04
How do you configure Jackson to serialize dates as ISO 8601 strings instead of timestamps?
SENIOR
05
Describe a real production incident you faced with JSON serialization and how you fixed it.
SENIOR
FAQ · 5 QUESTIONS
Frequently Asked Questions
01
What is Working with JSON in Java in simple terms?
It's the ability to convert Java objects to JSON strings and back using libraries like Jackson and Gson. Think of it as a translator between your Java code and the outside world.
Was this helpful?
02
Should I use Jackson or Gson for a new Spring Boot project?
Jackson is the default in Spring Boot and integrates deeply with the framework (e.g., message converters, actuator metrics). It supports YAML and XML if needed. Gson is lighter but requires manual configuration for Spring integration. For most Spring Boot projects, stick with Jackson.
Was this helpful?
03
Why does my deserialized object have null fields even though the JSON has them?
Check your class for setter methods or constructor parameters. If the library cannot match JSON keys to Java fields (e.g., mismatched names, missing setters), the field remains null. Use @JsonProperty to map names explicitly if they differ.
Was this helpful?
04
Can I use both Jackson and Gson in the same project?
Technically yes, but it's a bad idea. You'll have duplicate dependencies, potential classpath conflicts, and confusion over which annotations apply. Pick one library and use it everywhere — unless you're in a migration phase and plan to remove the old one.
Was this helpful?
05
How do I handle JSON with optional fields in Java?
Use Java Optional fields in your POJO and configure Jackson to retain Optional type info via JavaTimeModule. Gson does not support Optional natively; use null checks or write a TypeAdapter. Another approach: use @JsonProperty(required = false) and validate after deserialization.