java反射生成json需递归遍历字段、检测循环引用(用identityhashmap)、过滤static/transient字段,手动处理类型转换、格式化及安全控制。

Java 中通过反射遍历对象图并生成 JSON 字符串,核心在于递归访问字段、处理循环引用、过滤非业务字段,并控制格式化输出。不依赖 Jackson 或 Gson 等库也能实现,但需手动处理类型、访问权限、null 值和嵌套结构。
获取所有可读字段(含父类)
使用 Class.getDeclaredFields() 获取本类全部字段,再递归调用 getSuperclass() 向上收集;对每个字段设为 setAccessible(true) 突破 private 限制。注意跳过 static 和 transient 字段(通常不参与序列化)。
- 用
Field.get(obj)获取字段值,捕获IllegalAccessException - 对基本类型(int/boolean 等)自动装箱后统一按 Object 处理
- 忽略
getClass()、wait()等方法引入的伪字段(实际不会出现在 getDeclaredFields 中,无需额外过滤)
递归遍历与循环引用检测
对象图可能含环(如 A→B→A),直接递归会栈溢出。需维护一个 IdentityHashMap<object boolean></object> 记录已访问对象的内存地址(用 System.identityHashCode() 或直接存 Object 引用),遇到重复引用时输出占位符(如 "$ref": "id001")或跳过。
- 每次进入新对象前检查是否已存在该引用,存在则返回
{"$ref": "obj_"+hashCode} - 首次访问时记录该对象并分配唯一 ID(可用计数器 + hashCode 组合)
- 集合类(List/Map)同样需单独判断是否已遍历,避免重复展开
类型适配与 JSON 元素拼接
根据字段值类型决定 JSON 片段格式:String 加双引号;数字不加引号;Boolean 输出 true/false;null 输出 null;数组/Collection 输出 [...];Map 或普通 Bean 输出 {...}。拼接时注意逗号分隔、缩进换行等格式化细节。
- 用 StringBuilder 累加,避免频繁字符串拼接
- 每层嵌套增加 2 或 4 个空格缩进,用递归深度控制
- Map 的 key 必须是 String,非 String key(如 Integer)需调用
toString() - 日期类型(Date/LocalDateTime)默认转为 ISO 格式字符串,或预留自定义格式化接口
控制输出粒度与安全过滤
生产环境需支持白名单字段、忽略敏感属性(如 password)、跳过 null 值、限制最大递归深度防止栈溢出或 DoS 攻击。
- 提供注解(如
@JsonIgnore、@JsonInclude(Include.NON_NULL))模拟主流库行为 - 递归深度超限时抛异常或截断,例如超过 10 层后输出
"$truncated": true - 对 byte[] 默认 Base64 编码,而非尝试 toString() 导致乱码
- 枚举类型调用
name()或toString(),由配置决定
不复杂但容易忽略边界情况——比如 final 字段无法修改但可读取,包装类型 null 值要如实输出,泛型擦除后 Map 的 value 类型无法精确还原。写好基础版后,建议逐步叠加注解支持、定制序列化器、线程安全缓存字段信息等能力。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











