如何把 JSON 快速转成 Java 实体类(含注解与 List 嵌套)
对接接口返回一段 JSON,要生成对应的 Java 实体类(POJO)。手写几十个字段 + getter/setter + 注解,既枯燥又易错。能不能自动转?
能。下面讲清楚 JSON → Java 类的类型映射与注解选择,并一步步用本地工具生成。
JSON 类型到 Java 类型的映射
| JSON 类型 | Java 类型 | 备注 |
|---|---|---|
对象 {} | 嵌套 class / Map<String,Object> | |
数组 [] | List<T> | 推荐用 List 而非数组 |
字符串 "a" | String | |
| 整数 | Long / Integer | 大数用 Long,避免溢出 |
| 小数 | Double / BigDecimal | 金额用 BigDecimal |
| 布尔 | Boolean | |
null | 对应包装类型(如 Integer) | 用包装类区分 null 与 0 |
| 混合数组 | List<Object> | 尽量避免 |
序列化注解怎么选
Java 生态常用三套 JSON 库,注解写法不同:
| 库 | 注解 | 示例 |
|---|---|---|
| Jackson | @JsonProperty("name") | 最主流,Spring 默认 |
| Gson | @SerializedName("name") | Android 常用 |
| 原生 | 字段名需与 JSON 一致 | 不推荐,灵活性差 |
Spring Boot 项目默认 Jackson,下面示例都用 Jackson。
一步步生成(无需装插件)
用本站 JSON 转 Java 工具,浏览器本地完成,JSON 不上传:
- 打开 JSON 转 Java。
- 粘贴 JSON(对象或数组)。
- 配置:
- 根类名(如
User、OrderResponse); - 包名(如
com.example.dto)——填写后输出顶部会带package …;; - 是否生成 Lombok
@Data(省 getter/setter); - 注解风格:无 / Jackson
@JsonProperty/ Gson@SerializedName。
- 根类名(如
- 编辑选项时输出会即时更新,复制 Java 类进项目即可。
- 需要其他语言?可再用 JSON 转 Go 或 JSON 转 TypeScript。
完整例子
输入 JSON:
{
"id": 1024,
"name": "Alice",
"vip": true,
"tags": ["java", "api"],
"address": {
"city": "Shanghai",
"zip": "200000"
}
}
生成的 Java 类(Jackson + Lombok):
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
public class User {
@JsonProperty("id")
private Long id;
@JsonProperty("name")
private String name;
@JsonProperty("vip")
private Boolean vip;
@JsonProperty("tags")
private List<String> tags;
@JsonProperty("address")
private Address address;
}
@Data
public class Address {
@JsonProperty("city")
private String city;
@JsonProperty("zip")
private String zip;
}
进阶建议
- 金额用
BigDecimal:double有精度问题,涉钱务必用BigDecimal。 - 大整数用
Long:JSON 数字超过int范围(21 亿)会溢出。 - 先格式化:杂乱 JSON 先用 JSON 格式化工具 整理,类型推断更准。
- 区分 null 与零值:用包装类(
Integer而非int),否则无法判断字段是否返回。 - 时间字段:JSON 时间多为字符串,Java 用
String或LocalDateTime+ 自定义反序列化器。
常见问题
Q:数组元素类型不一致怎么办?
用 List<Object>,自己再判断;或推动接口方统一结构。
Q:字段名是蛇形 user_name,Java 要用驼峰怎么办?
用 @JsonProperty("user_name") 映射,Java 字段写 userName 即可。
Q:要不要 Lombok? 团队统一用 Lombok 能大幅减少样板代码;若项目禁用 Lombok,工具也可生成普通 getter/setter。
Q:List 和数组选哪个?
优先 List<T>,反序列化更灵活、支持动态长度;除非有明确性能/互操作要求才用数组。
Java 三坑:日期、泛型、Optional
日期:生成的 POJO 默认把时间戳映射 String——换 OffsetDateTime/Instant 就改变反序列化要求(Jackson 要 JavaTimeModule;Gson 要自己的适配器)。epoch 毫秒字段映射 long,静默丢时区——「哪些字段是 epoch、哪些是 ISO 字符串」的审查属于每次 schema 导入。泛型:List 在运行时擦除——异构对象的数组无错地反序列化,首个 cast 才炸。Optional:语言作者自己不鼓励用于字段位置(Optional 为返回值设计)——可空对象字段加 null 检查或 @Nullable 才是 Java 惯用法。
Records:2021+ 的答案,没有转换器默认用
Java record(record User(String id, String name) )一行给出不可变数据类 + 生成的 equals/hashCode/toString——恰好是 JSON POJO 想要的一切。多数生成器仍输出老式类(私有字段 + 六十行 getter/setter),因为 record 要 Java 16+。项目在现代 JDK 上,把生成输出转 record 是五分钟的机械清理、永久受益:并发代码免费获得不可变性,Jackson/Gson 都已原生支持。唯一代价:record 是 final 的——不能继承,而 API DTO 几乎总是就该不可继承。
未知字段三姿态
上游 API 凌晨两点加字段、严格反序列化器抛 UnrecognizedPropertyException——经典生产事故。三种姿态:忽略未知(@JsonIgnoreProperties——API 客户端的默认选择)、快速失败(内部契约里 schema 漂移更糟时保留异常)、捕获进 map(审计/回显场景)。每个边界选定一种写下来,让生成代码携带注解而不是靠全局 ObjectMapper 配置——下一个服务会静默漏掉那个配置。
基本类型与包装类型推断
生成器常从非 null 样例推出 int / long / boolean。直到后来某次载荷同键给了 null,反序列化才炸或意外装箱。接口边界除非契约写明「字段始终存在」,否则优先包装类(Integer、Long、Boolean)。超过 Number.MAX_SAFE_INTEGER 的大整数应走无损路径落到 long(超过 64 位再用 BigInteger);金额字段即便样例像普通浮点,仍应用 BigDecimal。
小结
JSON 转 Java 实体类 = 按类型映射生成带 Jackson/Gson 注解的 POJO,注意金额用 BigDecimal、大数用 Long、null 用包装类。用本站的 JSON 转 Java 工具 在本地一键生成,JSON 不上传,更适合处理含敏感字段的接口数据。
实现注记
站内类型生成工具踩过的坑值得记录:异构数组曾把第一个元素之后的全部静默丢弃,修复后产出联合元素类型、类型名取单数化键名;键名没有可用单词字符时,PascalCase 转换回退到兜底名而不是产出非法标识符。喂样例时同理:数组里混着数字和字符串的字段,别只给第一条数据。
相关工具
相关文章
正则表达式匹配不上?排查这 6 个常见坑
正则表达式不匹配、regex匹配失败时如何排查?本文详解贪婪量词、标志位遗漏、特殊字符转义、环视断言、换行符处理、Unicode属性6大常见坑,附前后对比示例,帮你快速定位正则调试问题。
Hydration failed / Text content does not match 报错怎么解决?
Next.js/React SSR 最常见的水合报错完整指南:为什么服务端和客户端渲染不一致、时间戳/随机值/localStorage 三大来源、suppressHydrationWarning 的正确用法,配本站工具定位差异。
Cannot read properties of undefined (reading 'map') 报错怎么解决?
React/前端最常见运行时报错的完整排查指南:为什么 undefined.map 会报错、接口数据异步加载的正确处理、可选链与默认值防御、空状态渲染,配本站 JSON 工具实测定位。