JSON转Java
从JSON生成Java POJO类
JSON输入
Java输出
什么是JSON转Java类转换?
JSON转Java类转换是指将原始JSON对象生成Plain Old Java Object(POJO)定义,包含私有字段、getter和setter方法。Java没有内置的JSON类型系统,因此每个JSON API响应、配置文件或消息负载在以类型安全的方式处理之前,都需要对应的类定义。Jackson和Gson等库通过反射将JSON键映射到Java字段,但前提是类定义必须已经存在。
用于JSON反序列化的标准Java POJO为每个JSON键声明一个私有字段、一个无参构造函数以及每个字段对应的getter/setter方法对。嵌套JSON对象会生成独立的类。数组变为带有java.util.List导入的List<T>字段。基本JSON类型映射为Java基本类型(int、double、boolean)或在泛型中使用时的包装类型(Integer、Double、Boolean)。Null值通常映射为Object或可空引用类型。
手动编写这些类定义是重复性工作:读取每个JSON键,从值推断Java类型,将命名规范从camelCase JSON转换为camelCase Java字段,为嵌套对象创建PascalCase类名,并添加getter/setter样板代码。对于一个有15个字段和3个嵌套对象的JSON对象,这意味着要编写4个类、30多个方法,并保持一切一致。转换器能在毫秒内完成这一切。
为什么使用JSON转Java转换器?
手动从JSON创建Java POJO意味着检查每个字段、从示例值推断类型、编写getter/setter方法对,并对每个嵌套对象重复此过程。当API契约发生变更时,需要手动更新所有内容。转换器消除了这些机械性工作。
JSON转Java使用场景
JSON与Java类型映射
每种JSON值都映射到特定的Java类型。下表展示转换器如何将每种JSON类型翻译为其Java等价类型。替代项列显示在List<T>等泛型上下文中使用的包装类型,或Record等较新的Java特性。
| 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注解参考
使用Jackson或Gson反序列化JSON时,注解控制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是兼容性最广的传统模式。Record减少了不可变数据的样板代码。Lombok通过注解在编译时生成getter、setter和构造函数。
代码示例
以下示例展示如何配合Jackson使用生成的Java POJO进行反序列化,如何通过JavaScript和Python以编程方式生成Java类,以及如何使用jsonschema2pojo CLI工具进行批量生成。
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