JSON to Java Classes
JSON to Java generates records or POJOs from a sample document in your browser. Optional numeric fields are boxed — Integer rather than int — because a primitive cannot hold null, so a missing key deserializes to 0 and becomes indistinguishable from a real zero.
Empty JSON input (truncated document)
^
How does JSON to Java Classes work?
Java's primitive types make the optional-field question concrete rather than stylistic, and getting it wrong produces a bug that is genuinely hard to find.
A primitive cannot be absent
int count deserializes a missing count key to 0. No exception, no warning — and downstream there is no way to tell a record where the count was never sent from one where the count really was zero. The same applies to boolean, which becomes false, and double, which becomes 0.0. Optional and nullable fields are therefore boxed: Integer, Long, Double, Boolean, all of which can hold null and let you ask the question.
Generics cannot hold primitives at all
List<int> does not compile. Every list element is boxed regardless of optionality, which is why an array of integers becomes List<Integer>.
record or POJO
A record is the better default on Java 17 and later: immutable, no boilerplate, equals and hashCode and toString for free, and Jackson has supported them since 2.12. A POJO with private fields and getters and setters is what a codebase on Java 8 or a framework that requires a no-argument constructor will want, so both are available.
Jackson annotations carry the original key
Java convention is camelCase; JSON keys frequently are not. Rather than depend on a PropertyNamingStrategy being configured somewhere else, every component gets an explicit @JsonProperty with the exact key from the document. The class then binds correctly whatever the ObjectMapper is set to.
One public type per file
Java allows exactly one public top-level type per source file, so a document that produces several types does not compile as a single paste. The output says so in a header comment: save each type as <TypeName>.java, or nest them inside one outer class. Emitting a file that javac rejects without mentioning it is the kind of small dishonesty that wastes ten minutes.
Sample
[
{ "user_id": 1, "retries": 0, "tags": ["a"] },
{ "user_id": 2, "tags": [] }
]Generated
public record User(
@JsonProperty("user_id") int userId,
@JsonProperty("retries") Integer retries,
@JsonProperty("tags") List<String> tags
) {}What options and edge cases does JSON to Java Classes support?
| Parameter | Type | Default | Behaviour & edge cases |
|---|---|---|---|
| Shape | record / POJO | record | record on Java 17+ for an immutable DTO with no boilerplate. POJO for Java 8, or for anything that needs a no-argument constructor and setters. |
| Package | identifier | (none) | Adds a package declaration. Leave it empty for a scratch file; set it to match the directory the file will live in. |
| Jackson | boolean | on | Emits @JsonProperty with the exact JSON key, so binding does not depend on an ObjectMapper naming strategy configured elsewhere. |
| box optionals | boolean | on | An optional int becomes Integer. Turning this off makes a missing key deserialize to 0, which is indistinguishable from a real zero. |
| string | Java type | String | Detected formats are not mapped to Instant, LocalDate or UUID. Jackson needs JavaTimeModule registered for the first two, and it throws on any record whose format differs. |
| integer | Java type | int / long | long when any sample exceeds 2,147,483,647. A JSON number carries no declared width, so the width is read from the values. |
| array | Java type | List<T> | Elements are always boxed, because generics cannot hold primitives. A mixed array becomes List<Object>. |
| Nested object | type | own type | Promoted to its own record or class, declared before the type that uses it. Identical shapes share one type rather than generating numbered duplicates. |
Frequently asked questions
Why is one field int and another Integer?
The Integer appeared in some records and not others. A primitive int cannot hold null, so Jackson deserializes a missing key to 0 — and nothing downstream can tell that apart from a record that genuinely sent zero. Integer can be null, which makes the absence visible. Fields present in every record stay primitive, which is cheaper and simpler.
Can I paste the whole output into one file?
Not if it generated more than one type. Java allows exactly one public top-level type per source file, so javac will reject it. Save each type as <TypeName>.java, or make the nested ones static nested classes inside one outer class. The output says which case you are in at the top.
record or POJO?
record if you are on Java 17 or later and the object is data that arrived from somewhere: it is immutable, it gives you equals, hashCode and toString correctly, and Jackson has supported records since 2.12. POJO if you are on Java 8, if a framework requires a no-argument constructor and setters (older JPA, some Spring configurations), or if the object genuinely needs to be mutated after construction.
Why is my timestamp a String rather than Instant?
Because Jackson cannot parse it into Instant without JavaTimeModule registered, and because it throws on the first record whose format differs from what it expects. Real APIs send Unix seconds, Unix milliseconds, ISO 8601 with and without offsets, and occasionally something regional. The detected format is noted in the reference above so you can change the type deliberately and add a converter if the format needs one.
Do I need Lombok?
No, and the generator deliberately does not emit @Data or @Builder. On Java 17+ a record covers what Lombok's @Value was for, without an annotation processor in your build. The POJO output is plain Java with real getters and setters, which compiles anywhere. If your project already uses Lombok you can replace the accessors yourself, but nothing here requires it.
Is my JSON uploaded?
No. Parsing, type inference and rendering all run in your browser — open the Network panel while you paste and you will see nothing leave. The samples people paste into a class generator are usually real responses from a system they are integrating against, which is precisely the material that should not pass through an unknown server.