JSON to Java
Генерация Java POJO-классов из JSON
Ввод JSON
Вывод Java
Что такое конвертация JSON в Java-классы?
Конвертация JSON в Java-классы берёт исходный JSON-объект и создаёт определения Plain Old Java Object (POJO) с приватными полями, геттерами и сеттерами. В Java нет встроенной типовой системы для JSON, поэтому каждый API-ответ, конфигурационный файл или сообщение в очереди требует соответствующего класса, прежде чем с ним можно будет работать типобезопасно. Библиотеки Jackson и Gson сопоставляют ключи JSON с полями Java через рефлексию, но для этого определения классов должны существовать заранее.
Стандартный Java POJO для десериализации JSON объявляет приватное поле для каждого ключа JSON, конструктор без аргументов и пару геттер/сеттер для каждого поля. Вложенные JSON-объекты становятся отдельными классами. Массивы превращаются в поля типа List<T> с импортом java.util.List. Примитивные типы JSON соответствуют примитивам Java (int, double, boolean) или их типам-обёрткам (Integer, Double, Boolean) при использовании в обобщённых типах. Значения null обычно отображаются на Object или обнуляемый ссылочный тип.
Писать эти определения классов вручную — механическая работа. Нужно прочитать каждый ключ JSON, определить тип Java по значению, преобразовать именование из camelCase JSON в camelCase-поля Java, создать имена классов в PascalCase для вложенных объектов и добавить шаблонный код геттеров и сеттеров. Для JSON-объекта с 15 полями и 3 вложенными объектами это означает написание 4 классов, 30+ методов и поддержание согласованности всего этого. Конвертер делает то же самое за миллисекунды.
Зачем использовать конвертер JSON в Java?
Создавать Java POJO из JSON вручную — значит проверять каждое поле, угадывать типы по примерам значений, писать пары геттер/сеттер и повторять всё это для каждого вложенного объекта. При изменении API-контракта всё нужно обновлять вручную. Конвертер устраняет эту механическую работу.
Сценарии использования JSON to Java
Таблица соответствия типов JSON и Java
Каждое значение JSON соответствует определённому Java-типу. В таблице ниже показано, как конвертер транслирует каждый тип JSON в его Java-эквивалент. Столбец «Альтернатива» содержит типы-обёртки, используемые внутри обобщённых типов (например, List<T>), а также более новые возможности Java, такие как Records.
| Тип JSON | Пример | Тип Java | Альтернатива |
|---|---|---|---|
| string | "hello" | String | String |
| number (integer) | 42 | int | int / Integer |
| number (float) | 3.14 | double | double / Double |
| boolean | true | boolean | boolean / Boolean |
| null | null | Object | Object (or @Nullable String) |
| object | {"k": "v"} | NestedClass | Record (Java 16+) |
| array of strings | ["a", "b"] | List<String> | List<String> |
| array of objects | [{"id": 1}] | List<Item> | List<Item> |
| mixed array | [1, "a"] | List<Object> | List<Object> |
Справочник по Java JSON-аннотациям
При десериализации JSON с помощью Jackson или Gson аннотации управляют сопоставлением ключей JSON с полями Java, обработкой неизвестных полей и поведением при null-значениях. В этом справочнике рассмотрены аннотации, которые встречаются чаще всего при работе с генерируемыми POJO.
| Аннотация | Назначение | Библиотека |
|---|---|---|
| @JsonProperty("name") | Maps a JSON key to a Java field with a different name | Jackson |
| @SerializedName("name") | Same as @JsonProperty, but for the Gson library | Gson |
| @JsonIgnoreProperties | Ignores unknown JSON keys during deserialization instead of failing | Jackson |
| @Nullable | Marks a field as accepting null values from JSON input | JSR 305 / JetBrains |
| @NotNull | Enforces that a field must not be null, throws on violation | Bean Validation |
| @JsonFormat(pattern=...) | Defines a date/time format for serialization and deserialization | Jackson |
POJO vs Record vs Lombok
В Java есть три распространённых подхода к определению типизированных структур для хранения JSON-данных. Каждый подходит для своего стиля проекта и версии Java. POJO — традиционный паттерн с наибольшей совместимостью. Records сокращают шаблонный код для неизменяемых данных. Lombok генерирует геттеры, сеттеры и конструкторы во время компиляции через аннотации.
Примеры кода
Эти примеры показывают, как использовать сгенерированные Java POJO с Jackson для десериализации, как программно создавать Java-классы из JavaScript и Python, а также как применять CLI-инструмент jsonschema2pojo для пакетной генерации.
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
private int id;
private String name;
private String email;
private boolean active;
private double score;
private Address address;
private List<String> tags;
// getters and setters omitted for brevity
public static void main(String[] args) throws Exception {
String json = "{\"id\":1,\"name\":\"Alice\",\"email\":\"alice@example.com\",\"active\":true,\"score\":98.5,\"address\":{\"street\":\"123 Main St\",\"city\":\"Springfield\",\"zip\":\"12345\"},\"tags\":[\"admin\",\"user\"]}";
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(json, User.class);
System.out.println(user.getName()); // -> Alice
}
}
class Address {
private String street;
private String city;
private String zip;
// getters and setters
}// Minimal JSON-to-Java-POJO generator in JS
function jsonToJava(obj, name = "Root") {
const classes = [];
function infer(val, fieldName) {
if (val === null) return "Object";
if (typeof val === "string") return "String";
if (typeof val === "number") return Number.isInteger(val) ? "int" : "double";
if (typeof val === "boolean") return "boolean";
if (Array.isArray(val)) {
const first = val.find(v => v !== null);
if (!first) return "List<Object>";
const elem = infer(first, fieldName);
const boxed = elem === "int" ? "Integer" : elem === "double" ? "Double" : elem === "boolean" ? "Boolean" : elem;
return `List<${boxed}>`;
}
if (typeof val === "object") {
const cls = fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
build(val, cls);
return cls;
}
return "Object";
}
function build(obj, cls) {
const fields = Object.entries(obj).map(([k, v]) => {
const type = infer(v, k);
return ` private ${type} ${k};`;
});
classes.push(`public class ${cls} {\n${fields.join("\n")}\n}`);
}
build(obj, name);
return classes.join("\n\n");
}
console.log(jsonToJava({ id: 1, name: "Alice", scores: [98, 85] }, "User"));
// public class User {
// private int id;
// private String name;
// private List<Integer> scores;
// }import json
def json_to_java(obj: dict, class_name: str = "Root") -> str:
classes = []
def infer(val, name):
if val is None:
return "Object"
if isinstance(val, bool):
return "boolean"
if isinstance(val, int):
return "int"
if isinstance(val, float):
return "double"
if isinstance(val, str):
return "String"
if isinstance(val, list):
if not val:
return "List<Object>"
elem = infer(val[0], name)
boxed = {"int": "Integer", "double": "Double", "boolean": "Boolean"}.get(elem, elem)
return f"List<{boxed}>"
if isinstance(val, dict):
cls = name[0].upper() + name[1:]
build(val, cls)
return cls
return "Object"
def build(obj, cls):
fields = [f" private {infer(v, k)} {k};" for k, v in obj.items()]
classes.append(f"public class {cls} {{\n" + "\n".join(fields) + "\n}")
build(obj, class_name)
return "\n\n".join(classes)
data = json.loads('{"id": 1, "name": "Alice", "tags": ["admin"]}')
print(json_to_java(data, "User"))
# public class User {
# private int id;
# private String name;
# private List<String> tags;
# }# Install jsonschema2pojo (requires Java 8+)
# Download from https://github.com/joelittlejohn/jsonschema2pojo
# Generate POJOs from a JSON file
jsonschema2pojo --source user.json --target src/main/java \
--source-type json --annotation-style jackson2
# Generate with Gson annotations instead
jsonschema2pojo --source user.json --target src/main/java \
--source-type json --annotation-style gson
# From a JSON string via stdin
echo '{"id": 1, "name": "Alice", "tags": ["admin"]}' | \
jsonschema2pojo --source-type json --annotation-style jackson2 \
--target src/main/java --target-package com.example.model