JSON to Java
Generování Java POJO tříd z JSON
Vstup JSON
Výstup Java
Co je převod JSON na Java třídy?
Převod JSON na Java třídy vezme surový JSON objekt a vytvoří definice Plain Old Java Object (POJO) s privátními poli, gettery a settery. Java nemá vestavěný typový systém pro JSON, takže každá JSON API odpověď, konfigurační soubor nebo zpráva vyžaduje odpovídající třídu, než s ní můžete pracovat typově bezpečně. Knihovny jako Jackson a Gson mapují JSON klíče na Java pole pomocí reflexe, ale vyžadují, aby definice tříd existovaly předem.
Standardní Java POJO pro deserializaci JSON deklaruje privátní pole pro každý JSON klíč, konstruktor bez argumentů a pár getter/setter pro každé pole. Vnořené JSON objekty se stávají samostatnými třídami. Pole se stávají poli List<T> s importem java.util.List. Primitivní JSON typy se mapují na Java primitivy (int, double, boolean) nebo jejich obalové typy (Integer, Double, Boolean) při použití uvnitř generik. Hodnoty null se typicky mapují na Object nebo na referenční typ připouštějící null.
Ruční psaní těchto definic tříd je opakující se práce. Čtete každý JSON klíč, určujete Java typ z hodnoty, převádíte pojmenovací konvence z camelCase JSON na camelCase Java pole, vytváříte PascalCase názvy tříd pro vnořené objekty a přidáváte getter/setter šablony. Pro JSON objekt s 15 poli a 3 vnořenými objekty to znamená napsat 4 třídy, více než 30 metod a udržovat vše konzistentní. Převodník to zvládne v milisekundách.
Proč používat převodník JSON na Java?
Ruční vytváření Java POJO z JSON znamená procházet každé pole, odvozovat typy z ukázkových hodnot, psát páry getter/setter a opakovat celý proces pro každý vnořený objekt. Když se API kontrakt změní, vše aktualizujete ručně. Převodník tuto mechanickou práci odstraní.
Případy použití JSON na Java
Mapování typů JSON na Java
Každá JSON hodnota se mapuje na specifický Java typ. Tabulka níže ukazuje, jak převodník překládá každý JSON typ na jeho Java ekvivalent. Sloupec Alternativa zobrazuje obalové typy používané v generických kontextech jako List<T> nebo novější Java funkce jako Records.
| Typ JSON | Příklad | Typ Java | Alternativa |
|---|---|---|---|
| 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> |
Přehled Java JSON anotací
Při deserializaci JSON pomocí Jackson nebo Gson anotace řídí, jak se JSON klíče mapují na Java pole, jak jsou zpracovávána neznámá pole a jak jsou ošetřeny hodnoty null. Tento přehled zahrnuje anotace, se kterými se při práci s generovanými POJO setkáte nejčastěji.
| Anotace | Účel | Knihovna |
|---|---|---|
| @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 nabízí tři běžné přístupy pro definování typovaných struktur pro uchovávání JSON dat. Každý se hodí pro jiný styl projektu a verzi Javy. POJO jsou tradiční vzor s nejširší kompatibilitou. Records snižují šablonový kód pro neměnitelná data. Lombok generuje gettery, settery a konstruktory při kompilaci pomocí anotací.
Příklady kódu
Tyto příklady ukazují, jak používat generované Java POJO s Jackson pro deserializaci, jak programově vytvářet Java třídy z JavaScriptu a Pythonu a jak používat nástroj jsonschema2pojo CLI pro dávkové generování.
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