How to Convert JSON to Java (Jackson POJOs, Done Right)

To read JSON in Java you need a class to bind it to, and writing those POJOs by hand is tedious: every field needs the right type, and every field whose name differs from the JSON key needs a Jackson annotation or it silently stays null. Generating the classes from a real sample fixes both. This guide covers how the mapping works, the fastest way to do it, and the Java-specific gotchas around annotations, boxed types, and List.

The fastest route: a browser generator

For a one-off, paste the JSON into the JSON to Java converter. It reads the sample, infers the type of every field, and writes classes ready for Jackson: nested objects become their own classes, arrays become List types, numbers resolve to Long or Double, and each field carries a @JsonProperty tag with the imports you need. Because it runs entirely in your browser, the JSON never leaves your machine, which matters when the sample is a real production response.

If the JSON will not convert, it is almost always invalid rather than genuinely unconvertible. Run it through the JSON parser to find the exact syntax error, or format it so you can see the structure first.

How JSON maps to Java

A generator makes the same decisions every time. Knowing them tells you what to expect.

Here is the shape of a simple conversion:

{ "id": 1, "name": "Ada", "tags": ["admin", "dev"] }

becomes:

import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;

public class Root {
    @JsonProperty("id")
    public Long id;
    @JsonProperty("name")
    public String name;
    @JsonProperty("tags")
    public List<String> tags;
}

Why @JsonProperty matters

Jackson maps JSON keys to Java fields by name. When your field is userId but the JSON key is user_id, Jackson will not connect them unless you either configure a global naming strategy or annotate the field:

@JsonProperty("user_id")
public Long userId;

Without that, userId quietly stays null after deserialization, which is one of the most common “my object is empty” bugs in Java. Generation removes it: every field gets the correct tag automatically, so the class binds no matter how the keys are named.

Why boxed types, not primitives

The generator uses Long, Double, and Boolean rather than long, double, and boolean. The reason is null. A primitive long cannot be null, so if the JSON omits the field or sends null, Jackson has nowhere to put the absence and you get 0 instead, which is indistinguishable from a real zero. Boxed wrapper types can be null, so they represent JSON faithfully. For any field that might be absent, boxed is the safe default, and generated POJOs use it throughout.

When you see Object

A field that is only ever null, an empty array, or holds more than one unrelated type has no single concrete Java type, so it falls back to Object (or List<Object> for a mixed array). That is a lack of evidence, not a bug. Populate those fields in the sample to get precise types, and reach for the JSON viewer to confirm the shape of a deeply nested payload before you convert.

Deserializing with Jackson

Once you have the classes, binding is one call. Keep the root class public in its own file, then:

ObjectMapper mapper = new ObjectMapper();
Root order = mapper.readValue(json, Root.class);

A couple of options are worth knowing. mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) stops Jackson throwing when the JSON has keys your class does not declare, which is useful for third-party APIs that add fields over time. And if you prefer getters and setters or immutability, generate the fields here and layer Lombok (@Data) or records on top.

The gotchas that bite

Frequently asked questions

How do I convert JSON to a Java class?
Paste the JSON into the JSON to Java converter and it writes Jackson-ready POJOs, inferring nested classes, List types, Long/Double, and @JsonProperty tags. Then deserialize with ObjectMapper.readValue.

Why is my Java object empty after parsing JSON?
Almost always a field name that does not match the JSON key and no @JsonProperty tag, so Jackson cannot bind it. Generating the class gives every field the correct tag.

Should I use Long or long?
Use the boxed Long for JSON that may omit or null the field, because a primitive long cannot be null and will become 0 instead. The generator uses boxed types throughout for this reason.

How do I ignore extra JSON fields?
Set mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) or annotate the class with @JsonIgnoreProperties(ignoreUnknown = true), so new keys from an API do not break deserialization.

For the format underneath all this, see the guide on what JSON is, the same idea for Go in converting JSON to Go structs, and the roundup of free JSON tools for the rest of the toolkit.

Leave a Reply

Your email address will not be published. Required fields are marked *