Skip to content

Formatters & Code

JSON to Java POJO

Emit a Java POJO from a JSON sample.

Runs in your browser
JSON · source
lines: 17chars: 261size: 261 B
Java POJO · result
lines: 51chars: 1624size: 1.6 KB
live

Understanding JSON → Java

Jackson, and a hundred annotations.

The two-decade tradition of Java JSON handling, why records changed everything in Java 14, and the annotations that distinguish a working POJO from a broken one.

Jackson is the de-facto library.

Java has no JSON support in the standard library. Every codegen tool assumes Jackson (com.fasterxml.jackson.databind) — the most-used Java library on Maven Central, the default in Spring Boot, the basis for almost every server-side framework's serialization. The generated POJOs look like normal Java but get annotated with Jackson's @JsonProperty, @JsonIgnoreProperties, @JsonInclude markers that tell the library how to map fields.

Classic POJO vs record.

A classic POJO has private fields, a no-arg constructor, getters, setters, and an equals/hashCode pair — easily 80 lines for a 5-field DTO. Java 14 records collapse the same idea to one line: record User(@JsonProperty("user_id") int userId, String name) {}. Records are immutable, generate equals/hashCode/toString automatically, and read like the data they describe. Modern codegen tools emit records by default and fall back to classic POJOs only when the project targets Java 8 or 11.

The @JsonProperty annotation.

JSON keys are typically snake_case; Java conventions are camelCase. Bridging them is one annotation: @JsonProperty("user_id") on a field named userId tells Jackson to read and write the JSON as user_id regardless of what Java calls it. Without the annotation, Jackson looks for an exact name match — and silently treats the field as missing if it can't find it. The most common Java JSON bug is "the field is always null after deserialization", and 80 % of the time it's a missing or misspelled @JsonProperty.

A worked example.

From { "user_id": 7, "name": "Q", "tags": ["a"] } a record emits: public record User( @JsonProperty("user_id") int userId, String name, List<String> tags ) {} A classic POJO for the same shape is roughly five times longer — class declaration, private fields, a no-arg constructor, a full-args constructor, five getters and setters, plus Jackson's annotations on the fields. Records exist because the boilerplate actually got embarrassing.

Record form

Java 14+

One line; immutable; equals + hashCode + toString automatic.

record User(int userId, String name, List<String> tags) {}

= 3 lines, fully featured

Classic POJO

Java 8 / 11

No-arg ctor + getters + setters + equals/hashCode.

class User { private int userId; public int getUserId() {...} ... }

= ~80 lines for 3 fields

Optional and nullable types.

Java has two notions of "missing": primitive types (int, boolean) can't be null at all and default to their zero value; wrapper types (Integer, Boolean) can be null. Use wrappers when the JSON field is genuinely optional. Optional<T> is also valid, but is conventionally for return types, not fields — Jackson supports both. The choice matters for the same reason it matters in Go: a primitive int defaulting to 0 silently masks "this field was missing".

Polymorphic types — @JsonTypeInfo.

For tagged unions (an array of events of different shapes), Jackson supports @JsonTypeInfo(use = Id.NAME, property = "type") with @JsonSubTypes listing the possible variants. Done correctly, you get a base class or sealed interface and Jackson dispatches the right concrete type from the JSON's discriminator field. Codegen tools recognise discriminator patterns and emit the right shape; without explicit support, you get a flat class with every field optional, which is functionally broken.

Strictness — fail or ignore unknown fields.

By default Jackson fails when deserializing JSON with fields the target class doesn't have. For an internal API that's the right default — it catches drift. For a public- consumer scenario where the producer might add fields, you want @JsonIgnoreProperties(ignoreUnknown = true) on the class (or the global ObjectMapper setting). Choose explicitly per type; the default is good for service-to- service, not for evolving APIs.

Builders and Lombok.

Before records, projects often used Lombok's @Value and @Builder to eliminate boilerplate. They still work fine — and remain the go-to in projects that can't use records yet — but a record on Java 21 plus Jackson 2.15 is comparable in terseness without the annotation-processor dance. New projects on modern Java should prefer records; brownfield projects can keep Lombok.

Frequently asked questions

Quick answers.

What libraries are required for the output?

The generated POJOs are standard Java classes using vanilla syntax. Depending on your configuration, you may want to add `Jackson` or `Gson` annotations for custom key mapping.

How does it handle nested objects?

The tool recursively parses the JSON and creates separate static inner classes or individual class definitions for each nested object found in the hierarchy.

Does this tool support Java Records?

Currently, the output defaults to standard class definitions with modifiers. You can manually convert the generated fields into a Record for use in Java 14 or higher.

Is my data privacy protected?

Yes. The conversion logic is executed entirely via JavaScript within your browser session. No data is stored or sent to a backend during the process.

People also search for

Related tools

More in this room.

See all in Formatters & Code