Конвертер JSON в классы Java

Генерируйте из JSON классы Java с геттерами и сеттерами, а также класс Converter на базе Jackson.

Генерация Java POJO из JSON

Маппинг JSON в Java обычно означает написание POJO для каждого объекта — с приватными полями, геттерами, сеттерами и аннотациями. Конвертер генерирует их по примеру: каждый объект становится классом с аннотациями Jackson @JsonProperty на методах доступа, вложенные объекты — отдельными классами, массивы — типизированными массивами, а целые числа — long. Класс Converter с методами fromJsonString и toJsonString инкапсулирует настройку Jackson ObjectMapper, включая вспомогательные функции для разбора дат и времени.

Как пользоваться

  1. Вставьте пример JSON — например, REST-ответ, который получает ваше приложение на Spring или Android.
  2. Введите имя корневого класса, например Customer.
  3. Добавьте jackson-databind в сборку Maven или Gradle, вынесите каждый класс в отдельный .java-файл в своём пакете и вызовите Converter.fromJsonString(json).

Часто задаваемые вопросы

Почему результат такой длинный?
Java требует явных полей, геттеров и сеттеров, а сгенерированный Converter содержит вспомогательные функции для работы с датой и временем через API java.time. Если вам нужны только модели, скопируйте классы данных и используйте свой существующий ObjectMapper.
Можно ли использовать records или Lombok?
Для максимальной совместимости генератор пишет классические классы. После копирования их можно преобразовать в records (Java 16+) или пометить аннотацией @Data из Lombok — Jackson поддерживает оба варианта.
Работает ли это со Spring Boot?
Да. Spring Boot по умолчанию использует Jackson, поэтому аннотированные классы можно напрямую использовать как @RequestBody или типы ответа без класса Converter.

Пример: JSON в Java

Исходный JSON

{
  "customerId": 501,
  "fullName": "Grace Hopper",
  "vip": true,
  "addresses": [{ "city": "Arlington", "zip": "22201" }]
}

Сгенерированный код: Java (Customer)

// Converter.java

// To use this code, add the following Maven dependency to your project:
//
//
//     com.fasterxml.jackson.core     : jackson-databind          : 2.9.0
//     com.fasterxml.jackson.datatype : jackson-datatype-jsr310   : 2.9.0
//
// Import this package:
//
//     import io.quicktype.Converter;
//
// Then you can deserialize a JSON string with
//
//     Customer data = Converter.fromJsonString(jsonString);

package io.quicktype;

import java.io.IOException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import java.util.*;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;

public class Converter {
    // Date-time helpers

    private static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
            .appendOptional(DateTimeFormatter.ISO_DATE_TIME)
            .appendOptional(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
            .appendOptional(DateTimeFormatter.ISO_INSTANT)
            .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SX"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssX"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
            .toFormatter()
            .withZone(ZoneOffset.UTC);

    public static OffsetDateTime parseDateTimeString(String str) {
        return ZonedDateTime.from(Converter.DATE_TIME_FORMATTER.parse(str)).toOffsetDateTime();
    }

    private static final DateTimeFormatter TIME_FORMATTER = new DateTimeFormatterBuilder()
            .appendOptional(DateTimeFormatter.ISO_TIME)
            .appendOptional(DateTimeFormatter.ISO_OFFSET_TIME)
            .parseDefaulting(ChronoField.YEAR, 2020)
            .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
            .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
            .toFormatter()
            .withZone(ZoneOffset.UTC);

    public static OffsetTime parseTimeString(String str) {
        return ZonedDateTime.from(Converter.TIME_FORMATTER.parse(str)).toOffsetDateTime().toOffsetTime();
    }
    // Serialize/deserialize helpers

    public static Customer fromJsonString(String json) throws IOException {
        return getObjectReader().readValue(json);
    }

    public static String toJsonString(Customer obj) throws JsonProcessingException {
        return getObjectWriter().writeValueAsString(obj);
    }

    private static ObjectReader reader;
    private static ObjectWriter writer;

    private static void instantiateMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.findAndRegisterModules();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        SimpleModule module = new SimpleModule();
        module.addDeserializer(OffsetDateTime.class, new JsonDeserializer<OffsetDateTime>() {
            @Override
            public OffsetDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
                String value = jsonParser.getText();
                return Converter.parseDateTimeString(value);
            }
        });
        mapper.registerModule(module);
        reader = mapper.readerFor(Customer.class);
        writer = mapper.writerFor(Customer.class);
    }

    private static ObjectReader getObjectReader() {
        if (reader == null) instantiateMapper();
        return reader;
    }

    private static ObjectWriter getObjectWriter() {
        if (writer == null) instantiateMapper();
        return writer;
    }
}

// Customer.java

package io.quicktype;

import com.fasterxml.jackson.annotation.*;

public class Customer {
    private long customerID;
    private String fullName;
    private boolean vip;
    private Address[] addresses;

    @JsonProperty("customerId")
    public long getCustomerID() { return customerID; }
    @JsonProperty("customerId")
    public void setCustomerID(long value) { this.customerID = value; }

    @JsonProperty("fullName")
    public String getFullName() { return fullName; }
    @JsonProperty("fullName")
    public void setFullName(String value) { this.fullName = value; }

    @JsonProperty("vip")
    public boolean getVip() { return vip; }
    @JsonProperty("vip")
    public void setVip(boolean value) { this.vip = value; }

    @JsonProperty("addresses")
    public Address[] getAddresses() { return addresses; }
    @JsonProperty("addresses")
    public void setAddresses(Address[] value) { this.addresses = value; }
}

// Address.java

package io.quicktype;

import com.fasterxml.jackson.annotation.*;

public class Address {
    private String city;
    private String zip;

    @JsonProperty("city")
    public String getCity() { return city; }
    @JsonProperty("city")
    public void setCity(String value) { this.city = value; }

    @JsonProperty("zip")
    public String getZip() { return zip; }
    @JsonProperty("zip")
    public void setZip(String value) { this.zip = value; }
}

Преобразовать JSON в другие языки