JSON sang Java
Tạo lớp Java POJO từ JSON
Đầu vào JSON
Đầu ra Java
Chuyển đổi JSON sang lớp Java là gì?
Chuyển đổi JSON sang lớp Java lấy một đối tượng JSON thô và tạo ra các định nghĩa Plain Old Java Object (POJO) với các trường private, getters và setters. Java không có hệ thống kiểu JSON tích hợp sẵn, vì vậy mọi phản hồi API JSON, file cấu hình hoặc payload tin nhắn đều cần một lớp tương ứng trước khi bạn có thể làm việc với nó theo cách an toàn kiểu. Các thư viện như Jackson và Gson ánh xạ các khóa JSON sang trường Java thông qua reflection, nhưng chúng yêu cầu các định nghĩa lớp phải tồn tại trước.
Một POJO Java chuẩn để giải tuần tự hóa JSON khai báo một trường private cho mỗi khóa JSON, một constructor không tham số, và một cặp getter/setter cho mỗi trường. Các đối tượng JSON lồng nhau trở thành các lớp riêng biệt. Mảng trở thành các trường List'<'T'>' với lệnh import java.util.List. Các kiểu JSON nguyên thủy ánh xạ sang kiểu nguyên thủy Java (int, double, boolean) hoặc kiểu wrapper của chúng (Integer, Double, Boolean) khi dùng bên trong generics. Giá trị null thường ánh xạ sang Object hoặc kiểu tham chiếu nullable.
Viết các định nghĩa lớp này bằng tay rất lặp đi lặp lại. Bạn phải đọc từng khóa JSON, xác định kiểu Java từ giá trị, chuyển đổi quy ước đặt tên từ camelCase JSON sang trường Java camelCase, tạo tên lớp PascalCase cho các đối tượng lồng nhau và thêm phần getter/setter. Với một đối tượng JSON có 15 trường và 3 đối tượng lồng nhau, điều đó có nghĩa là viết 4 lớp, hơn 30 phương thức và giữ cho mọi thứ nhất quán. Một bộ chuyển đổi thực hiện việc này trong vài mili giây.
Tại sao dùng bộ chuyển đổi JSON sang Java?
Tạo thủ công các Java POJO từ JSON đòi hỏi kiểm tra từng trường, suy luận kiểu từ giá trị mẫu, viết các cặp getter/setter và lặp lại quá trình này cho mọi đối tượng lồng nhau. Khi hợp đồng API thay đổi, bạn phải cập nhật mọi thứ bằng tay. Một bộ chuyển đổi loại bỏ công việc lặp đi lặp lại đó.
Các trường hợp sử dụng JSON sang Java
Bảng ánh xạ kiểu JSON sang Java
Mỗi giá trị JSON ánh xạ sang một kiểu Java cụ thể. Bảng dưới đây cho thấy bộ chuyển đổi dịch từng kiểu JSON sang tương đương Java như thế nào. Cột Thay thế hiển thị các kiểu wrapper dùng trong ngữ cảnh generic như List'<'T'>', hoặc các tính năng Java mới hơn như Records.
| Kiểu JSON | Ví dụ | Kiểu Java | Thay thế |
|---|---|---|---|
| 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> |
Tham chiếu Annotation JSON trong Java
Khi giải tuần tự hóa JSON với Jackson hoặc Gson, các annotation kiểm soát cách ánh xạ khóa JSON sang trường Java, cách xử lý các trường không xác định và cách xử lý giá trị null. Tài liệu tham chiếu này bao gồm các annotation bạn sẽ gặp thường xuyên nhất khi làm việc với các POJO được tạo.
| Annotation | Mục đích | Thư viện |
|---|---|---|
| @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 có ba cách tiếp cận phổ biến để định nghĩa các cấu trúc có kiểu chứa dữ liệu JSON. Mỗi cách phù hợp với một phong cách dự án và phiên bản Java khác nhau. POJO là pattern truyền thống với khả năng tương thích rộng nhất. Record giảm boilerplate cho dữ liệu bất biến. Lombok tạo getters, setters và constructors tại thời điểm biên dịch thông qua annotation.
Ví dụ mã nguồn
Các ví dụ này cho thấy cách sử dụng Java POJO được tạo với Jackson để giải tuần tự hóa, cách tạo các lớp Java theo chương trình từ JavaScript và Python, và cách dùng công cụ CLI jsonschema2pojo để tạo hàng loạt.
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