JSON to Java POJO
Generate Java POJOs or records with the right annotation stack from sample JSON — entirely on this device.
The generated Java appears here as you type.
Press ? for shortcuts
Do it offline:$ quicktype --lang java sample.json -o Root.java
How to use it
- Paste a JSON payload or drop a .json file into the input pane — the Java regenerates a moment after you stop typing.
- Add tabs with more payloads from the same endpoint; a field absent from one sample comes back boxed instead of primitive.
- Choose Jackson, Gson, Moshi or no annotations, POJO or record output, and set the top-level type name.
- Copy the compilation unit, download it as a .java file, or grab the zip when you want one file per class.
Paste one or more JSON samples and get Java source ready for a project: a class per object shape, camelCase fields, and the original key pinned in a Jackson, Gson or Moshi annotation. Switch between classic POJOs with accessors, Java 17+ records, or Lombok @Data, then copy one compilation unit or download a zip holding one file per class. Generation runs inside this browser tab.
Examples
{"order_id": 7, "items": [{"sku": "a-1", "qty": 2}]}import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
public class Order {
@JsonProperty("order_id")
private long orderId;
@JsonProperty("items")
private List<Item> items;
public long getOrderId() { return orderId; }
public void setOrderId(long value) { this.orderId = value; }
public List<Item> getItems() { return items; }
public void setItems(List<Item> value) { this.items = value; }
public static class Item {
@JsonProperty("sku")
private String sku;
@JsonProperty("qty")
private long qty;
public String getSku() { return sku; }
public void setSku(String value) { this.sku = value; }
public long getQty() { return qty; }
public void setQty(long value) { this.qty = value; }
}
}
Two object shapes in, two classes out: Order carries the list and Item is its element type. The wire key order_id lives in the annotation while the field reads as orderId with a getter and setter pair.
{"order_id": 4102, "items": [{"sku": "b-7", "qty": 1}]}import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
public record Root(
@JsonProperty("order_id") long orderId,
@JsonProperty("items") List<Item> items
) {
public record Item(
@JsonProperty("sku") String sku,
@JsonProperty("qty") long qty
) {}
}
The record form of the same shape: components replace fields, each annotation moves onto its component, and no accessor methods appear — a record derives accessors, equals, hashCode and toString itself, so only the nested Item record rides in the body.
{"order_id": 7}import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class Root {
@JsonProperty("order_id")
private long orderId;
}
One @Data annotation stands in for every accessor — Lombok writes them during compilation, so the generated source lists only the annotated fields.
{"class": "economy", "new": true}import com.fasterxml.jackson.annotation.JsonProperty;
public class Root {
@JsonProperty("class")
private String rootClass;
@JsonProperty("new")
private boolean rootNew;
public String getRootClass() { return rootClass; }
public void setRootClass(String value) { this.rootClass = value; }
public boolean getRootNew() { return rootNew; }
public void setRootNew(boolean value) { this.rootNew = value; }
}
class and new are reserved words in Java, so the fields become rootClass and rootNew and a chip reports each rename — the annotations keep deserialization reading the original keys.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
Swapping annotation stacks touches two lines
Generate the identical sample under Jackson and then Gson: the import flips to com.google.gson.annotations.SerializedName and every @JsonProperty becomes @SerializedName — nothing else moves. Moshi substitutes @Json(name = …) the same way, and None drops annotations for DTOs that never meet a mapper.
Records trade setters for guarantees
Record output targets Java 17 and newer: values arrive through the canonical constructor and never change afterwards, a natural fit for response payloads you only read. Pick POJO when something downstream mutates the object or the build still runs on Java 8 or 11.
Lombok is a build-time bargain
@Data keeps the source tiny but compiles only where the Lombok annotation processor is wired in. Its immutable sibling @Value overlaps with records on current JVMs — where records are available they need no extra dependency at all.
Why the getter is getIsActive()
A boolean key like isActive keeps its prefix as the field name and the accessor becomes getIsActive(). Bean-name inference would strip the prefix and expect a JSON property called active; the annotation pins the real key, so no mapper has to guess.
Deep payloads mean many classes
Each distinct object shape becomes its own class, so a deeply nested response can yield dozens. The default view folds them into one compilation unit as static nested classes; the zip download splits them into separate files ready for a package. Nesting past 256 levels is refused with a diagnostic naming that cap — nothing is silently truncated to fit.
Primitive fields are a presence claim
long, double and boolean appear only for fields present in every sample; a field missing somewhere is generated boxed so it can hold null. The boxed-numerics option forces wrapper types everywhere, which some mapping layers prefer.
Common errors
Sample 1: Unexpected '}' at line 1, column 16 — probable cause: trailing comma after the last property.- Java generation starts only once every sample parses as strict JSON. The diagnostic names the failing tab and carries line, column and a caret frame — fix the flagged character and the classes reappear without re-running anything.
Input is larger than the 10 MB limit for this tool.- Past the 10 MB cap the whole paste is declined; nothing is quietly cut to fit. Reduce the input to a few representative records, or point the quicktype command printed on this page at the complete file.
Samples total 2.0 MB — above the 2 MB advisory band. Generate from a representative sample, not the whole export.- Class shapes come from structure, not volume — a handful of varied records produces the same Java as a giant export. Above 2 MB the tool waits for an explicit run and shows this reminder; generation still proceeds when you trigger it.
FAQ
Which annotation stack should I pick — Jackson, Gson or Moshi?
Match the mapper your project already uses: Jackson is the default here and the one Spring Boot ships with, while Gson and Moshi are common in Android codebases. Whatever you choose, only the import and the annotation change — fields, types and nesting stay identical.
When are records the better choice than POJO classes?
Reach for records when payloads are read-only and the toolchain is Java 17 or newer — less code, immutability included. Stay with POJOs when values get set after construction or an older runtime is in the mix.
Does my JSON leave the browser while classes generate?
No. The generator is JavaScript running inside this page and samples are never posted anywhere — watch the network panel while generating to confirm. The zip download is assembled locally too.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Generate now, including past the 2 MB explicit-run threshold.
- ⌘/Ctrl + S
- Download the current view — the compilation unit as a .java file, or the zip in file-per-class layout.
- ⌘/Ctrl + C
- Copy all generated source while nothing is selected; a text selection copies normally.
- ⌘/Ctrl + Shift + C
- Copy all generated source even while a selection exists.
- t
- Switch the color theme (idle while typing in any field).
- ? or ⌘/Ctrl + /
- Open the help dialog listing these bindings.
- Esc
- Dismiss the topmost dialog; panes keep their content.