How to Convert JSON to Java Entity Class (with annotations and List nesting)
Integrating an API returns JSON; you need the matching Java entity class (POJO). Hand-writing dozens of fields + getters/setters + annotations is tedious and error-prone. Can you auto-convert?
Yes. Here are the type-mapping rules and annotation choices for JSON → Java, and how to generate step by step.
JSON type to Java type mapping
| JSON type | Java type | Notes |
|---|---|---|
Object {} | nested class / Map<String,Object> | |
Array [] | List<T> | Prefer List over array |
String "a" | String | |
| Integer | Long / Integer | Large numbers → Long (avoid overflow) |
| Decimal | Double / BigDecimal | Money → BigDecimal |
| Boolean | Boolean | |
null | wrapper type (e.g. Integer) | Distinguish null from 0 |
| Mixed array | List<Object> | Avoid if possible |
Which serialization annotation
Three common Java JSON libraries, different annotations:
| Library | Annotation | Example |
|---|---|---|
| Jackson | @JsonProperty("name") | Mainstream, Spring default |
| Gson | @SerializedName("name") | Common in Android |
| Native | field name must match JSON | Not recommended |
Spring Boot defaults to Jackson—examples below use it.
Step-by-step generation (no plugin)
Use this site's JSON to Java tool—runs locally, JSON never uploaded:
- Open JSON to Java.
- Paste JSON (object or array).
- Configure:
- Root class name (e.g.
User,OrderResponse); - Package (e.g.
com.example.dto) — emitted as apackage …;line when set; - Generate Lombok
@Data(skip getters/setters); - Annotation style: none, Jackson
@JsonProperty, or Gson@SerializedName.
- Root class name (e.g.
- Output updates as you edit—copy the Java classes into the project.
- Need other languages? Use JSON to Go or JSON to TypeScript.
Full example
Input JSON:
{
"id": 1024,
"name": "Alice",
"vip": true,
"tags": ["java", "api"],
"address": {
"city": "Shanghai",
"zip": "200000"
}
}
Generated Java (Jackson + Lombok):
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
public class User {
@JsonProperty("id")
private Long id;
@JsonProperty("name")
private String name;
@JsonProperty("vip")
private Boolean vip;
@JsonProperty("tags")
private List<String> tags;
@JsonProperty("address")
private Address address;
}
@Data
public class Address {
@JsonProperty("city")
private String city;
@JsonProperty("zip")
private String zip;
}
Advanced tips
- Money →
BigDecimal:doublehas precision issues; always useBigDecimalfor currency. - Large integers →
Long: JSON numbers beyondintrange (2.1B) overflow. - Format first: tidy messy JSON with the JSON formatter for better inference.
- null vs zero: use wrapper classes (
Integernotint) so you can tell if a field was returned. - Time fields: JSON times are usually strings; use
StringorLocalDateTime+ custom deserializer.
The Java-specific traps: dates, generics, optionals
Dates: generated POJOs map timestamp strings to String by default — switching to OffsetDateTime or Instant changes the deserializer requirements (Jackson needs JavaTimeModule registered; Gson needs its own adapter). Epoch-milliseconds fields (createdAt: 1699012345678) map to long, silently losing timezone information — a review of "which fields are epoch, which are ISO strings" belongs in every schema import. Generics: List<OrderItem> erases at runtime — a JSON array of heterogeneous objects deserializes without error into a list whose elements fail at first cast. Optional: Optional<T> in field positions is discouraged by the language authors themselves (Optional was designed for return types); nullable object fields with null-checks, or @Nullable annotations, are the Java-idiomatic representation of absent JSON keys.
Records: the 2021+ answer nobody's converter defaults to
Java records (record User(String id, String name) {}) give immutable data classes with generated equals/hashCode/toString in one line — exactly what JSON POJOs want. Most generators still emit old-style classes with private fields and sixty lines of getters/setters because records require Java 16+. If your project is on a modern JDK, converting generated output to records is a mechanical five-minute cleanup that pays forever: immutability for free in concurrent code, and Jackson/Gson both support records natively now. The one trade: records are final — no inheritance hierarchies, which for API DTOs is almost always the right constraint anyway.
Unknown fields and strictness
A JSON response that grows a new field breaks strict deserializers (UnrecognizedPropertyException in Jackson's default configuration) — the classic production incident when an upstream API adds a key at 2am. The three postures: ignore unknowns (@JsonIgnoreProperties(ignoreUnknown = true) — resilient, the default choice for API clients), fail-fast (keep the exception for internal contracts where silent schema drift is worse), or capture (@JsonAnyGetter/@JsonAnySetter into a map — for audit/echo scenarios). Decide per boundary, write it down, and make the generated code carry the annotation rather than relying on a global ObjectMapper configuration that the next service silently misses.
Primitive vs wrapper inference
Generators often emit int / long / boolean from non-null sample values. That is fine until a later payload sends null for the same key — then deserialization fails or boxes unexpectedly. Prefer wrappers (Integer, Long, Boolean) at API boundaries unless the contract documents the field as always present. Large integers beyond Number.MAX_SAFE_INTEGER should stay on a lossless path into long (or BigInteger when they exceed 64-bit); money fields still want BigDecimal even when the sample looks like a plain float.
FAQ
Q: Array elements inconsistent types?
Use List<Object> and judge yourself; or push the API to unify structure.
Q: Field is snake_case user_name, Java wants camelCase?
Map with @JsonProperty("user_name"); write the Java field as userName.
Q: Use Lombok? If the team standardizes on it, it cuts boilerplate massively; if banned, the tool can emit plain getters/setters.
Q: List or array?
Prefer List<T>—more flexible for dynamic length; use arrays only for specific perf/interop needs.
Summary
JSON to Java POJO = generate annotated classes by type mapping; money → BigDecimal, large numbers → Long, null → wrapper. Use this site's JSON to Java tool to generate locally—JSON not uploaded, safer for sensitive payloads.
Implementation notes
Two scars from this site's type generator are worth recording: heterogeneous arrays once silently dropped everything after the first element, and the fix now emits a union element type named after the singularized key; keys with no usable word characters fall back to a safe placeholder name during PascalCase conversion instead of producing an illegal identifier. The same caution applies to your samples — for a field whose array mixes numbers and strings, don't feed the generator only the first record.
Related Tools
Related Articles
Online CSS Minifier: Reduce CSS File Size for Better Performance
Learn how to minify CSS safely: whitespace, comments, hex shortening, zero-unit elision, calc protection, and UTF-8 byte savings — with an online tool you can use locally.
Regex Not Matching? Troubleshoot These 6 Common Pitfalls
How to troubleshoot when a regex doesn't match or matching fails? This article walks through 6 common pitfalls — greedy quantifiers, missing flags, unescaped special chars, lookaround assertions, newline handling, and Unicode properties — with before/after examples to help you quickly locate regex debugging issues.
How to Fix 'Hydration failed / Text content does not match' in Next.js
The complete guide to Next.js/React SSR hydration errors: why server and client renders diverge, the three usual suspects (timestamps, random values, localStorage), correct suppressHydrationWarning usage, and a ClientOnly pattern for browser-only widgets.