Classes or recordsReserved-word safeBigDecimal option

JSON to Java Class Converter

Generate Java classes with getters, or Java 16 records, from a JSON sample — with nested types, List generics and reserved-word handling. All processing happens locally in your browser.

Java type generation

Turn a JSON sample into Java classes or records

Fields are merged across every element of an array, so a key that appears in only some elements is still generated and boxed so it can be null. Reserved words and awkward keys are renamed to valid identifiers.

Classes1
Fields5
Root typeRoot
Inference notes0
InputJSON sample
OutputJava classes
import com.fasterxml.jackson.annotation.JsonProperty;

public class Root {
    private int id;
    @JsonProperty("user_name")
    private String userName;
    private String email;
    @JsonProperty("is_active")
    private boolean isActive;
    private double score;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public boolean isIsActive() {
        return isActive;
    }

    public void setIsActive(boolean isActive) {
        this.isActive = isActive;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }
}
Generation options
Nested types are named from their key.
Adds a package line at the top.
Values beyond int range are promoted to long automatically.
Use BigDecimal for currency to avoid binary rounding.

Bind the document to Root.

Load sampleLoad a sample

What is generated: classes or records

Java binds JSON to objects through a library — Jackson in most Spring projects, Gson elsewhere. Either way you need a type whose fields match the payload. This page generates that type in two shapes, and the choice is not cosmetic.

Classes with getters and setters

public class User {
    private int id;
    @JsonProperty("user_name")
    private String userName;
    private boolean isActive;

    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    ...
}

Mutable, works with every JSON library and every Java version, and satisfies the JavaBeans convention that Jackson and Gson both rely on by default. Verbose, but universally compatible.

Records

public record User(
    int id,
    String userName,
    boolean isActive
) {}

Immutable, and roughly a fifth of the code. Available from Java 16, and supported by Jackson 2.12 and later. Records give you a canonical constructor, accessors, equals, hashCode and toString for free.

The trade-off: because a record is immutable and its constructor requires every component, a payload missing a field will bind that component to null (or fail, depending on configuration). Records suit DTOs you read once; classes suit objects you build up incrementally.

How to generate types

  1. Paste a representative JSON sample Every element of an array is inspected, so a field present in only some records is still found.
  2. Pick classes or records Records need Java 16 or later and Jackson 2.12 or later.
  3. Choose numeric types int, long or BigInteger for whole numbers; double or BigDecimal for decimals. Values beyond int range are promoted to long automatically.
  4. Review the notes and split the files Java requires one public type per file. The output shows all generated types together for review.

Java identifier rules the generator has to work around

Java has stricter naming constraints than most languages JSON gets mapped to, and real payloads violate them regularly.

JSON key Java field Problem solved
user_name userName Underscores are not conventional in Java field names
class classValue class is a reserved word and will not compile
public publicValue Same — Java has 50+ reserved words
2fa_enabled fieldFaEnabled An identifier cannot start with a digit
request-id requestID A hyphen is not valid in an identifier
XMLPayload xmlPayload Leading acronym lowercased for camelCase

Every one of those renames breaks the automatic name-to-key mapping, which is exactly what @JsonProperty is for.

When @JsonProperty is actually needed

Jackson matches a JSON key to a field by name, so userName finds "userName" without help. It does not find "user_name". The annotation is only emitted when the names genuinely differ:

@JsonProperty("user_name")
private String userName;      // needed

private String email;         // not needed, names match

Annotating everything is harmless but adds noise, so it is skipped where it would do nothing. If your whole API is snake_case, a cleaner option is to configure the naming strategy once instead:

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class User { ... }

Examples: numeric types and why BigDecimal exists

JSON has one number type, so mapping it to Java's several is a decision rather than a detection.

Sample Default Consider instead
42 int long if IDs might exceed 2,147,483,647
9007199254740993 long (promoted) BigInteger beyond 64 bits
91.5 double Fine for measurements
19.99 as money double BigDecimal — always

The money case is worth spelling out because it causes real financial bugs. double is binary floating point, so decimal fractions have no exact representation:

double a = 0.1 + 0.2;
System.out.println(a);          // 0.30000000000000004

double total = 0;
for (int i = 0; i < 10; i++) total += 0.1;
System.out.println(total);      // 0.9999999999999999

BigDecimal b = new BigDecimal("0.1").add(new BigDecimal("0.2"));
System.out.println(b);          // 0.3

Note that BigDecimal must be constructed from a string. new BigDecimal(0.1) takes a double and inherits the same imprecision, which defeats the purpose. Jackson does this correctly when the target field is BigDecimal.

Primitives versus wrappers

An optional field is generated with a wrapper type — Integer rather than int — because a primitive cannot be null. Bind a missing JSON key to an int and you get 0, indistinguishable from a real zero. Bind it to Integer and you get null, which is the truth.

The same applies inside collections: Java generics cannot hold primitives, so a list of numbers is always List<Integer>, never List<int>.

Nested objects and collections

A nested object becomes its own type, named from its key:

{
  "orderId": "A-1001",
  "customer": {
    "id": 12,
    "address": { "line1": "1 Navy Way", "city": "Arlington" }
  }
}

generates Root, Customer and Address. Identical shapes are deduplicated, so billingAddress and shippingAddress with the same keys share one type rather than producing two identical classes.

An array of objects becomes List<T> with a singularised element name — "results" produces List<Result>. An empty array has no observable element type, so it becomes List<Object> and is flagged.

One public type per file. Java requires a public type to live in a file named after it, so a five-type result needs five files. Alternatively, make the nested types static inner classes of the root type and keep everything in one file — reasonable for DTOs that are only used together.

Use cases

  • Building a Spring Boot client. Paste a third-party response and get the DTO that RestTemplate or WebClient will bind to.
  • Writing a request body type. A sample of what clients post becomes your @RequestBody parameter type.
  • Consuming a Kafka message. Generate the value type for a deserialiser from one sample message.
  • Typing a configuration file. A JSON config becomes a @ConfigurationProperties class.
  • Modernising legacy code. Replace Map<String, Object> access with a real type and let the compiler find the field-name typos.
  • Checking an unfamiliar payload. The generated types plus the review notes act as a compact schema, showing which fields are inconsistent across records.

For other targets, JSON to Go generates structs from the same model. Java configuration often involves .properties files too — Properties to YAML and XML to Properties cover those. To validate the JSON first, use the JSON Schema Validator.

Privacy

Parsing and generation run in your browser; the JSON is not uploaded. Usage analytics record only the output style, the number of generated types and whether annotations were enabled — never the JSON or the generated code.

Frequently Asked Questions

Should I choose classes or records?

Records for read-only DTOs on Java 16+ with Jackson 2.12+ — they are immutable and far shorter. Classes when you need mutability, are on an older Java version, or use a framework that requires a no-argument constructor and setters, such as some JPA and older Spring configurations.

Why is @JsonProperty only on some fields?

Because Jackson matches names automatically when they are identical. An annotation on email for the key "email" does nothing. It is only emitted where the rename was unavoidable — snake_case keys, reserved words, keys starting with a digit, or keys containing hyphens.

Why is my optional field Integer rather than int?

A primitive cannot hold null, so a missing key would bind to 0 and be indistinguishable from a real zero. The wrapper type preserves the difference. This is the Java equivalent of the pointer types the Go generator uses for the same reason.

When should I use BigDecimal?

For any monetary or exact decimal value. double is binary floating point, so 0.1 + 0.2 is 0.30000000000000004 and repeated addition drifts. Construct BigDecimal from a string, never from a double — new BigDecimal(0.1) inherits the same imprecision it is meant to avoid.

Why do I get several types instead of one file?

Because each nested JSON object needs its own Java type, and Java requires one public type per file named after it. Split them into separate files, or convert the nested ones into static inner classes of the root type if they are only used together.

Does it generate Lombok annotations?

No. Lombok is a build-time dependency with its own annotation processor, so generating @Data would produce code that does not compile without it configured. Records give you most of what Lombok's @Value provides using only the standard language.

What happens to a JSON key called "class" or "public"?

It is renamed with a Value suffix — classValue, publicValue — because Java reserved words cannot be identifiers. A @JsonProperty annotation preserves the original key so binding still works against the real payload.