资讯动态

Java JSON序列化与反序列化实战:核心方法解析与避坑指南

发布时间:2026/8/17 17:32:54 来源:尧图企业网站定制
1. JSON序列化与反序列化的核心为什么是这三个方法如果你在Java项目里处理过JSON数据那么对JSON.parseArray()、JSON.parseObject()和JSON.toJSONString()这三个方法一定不会陌生。它们通常来自阿里巴巴开源的Fastjson库或者类似Gson、Jackson等库中功能对等的API。乍一看这不过是三个简单的工具方法一个用来把JSON字符串变成对象一个变成列表还有一个把对象变回字符串。但在我十多年的开发生涯里见过太多因为对这几个方法“想当然”的使用而引发的线上事故数据错乱、性能瓶颈、甚至安全漏洞。今天我们就抛开简单的API手册从实战角度深挖一下这三个看似基础的方法背后到底藏着多少需要你注意的细节。为什么是这三个方法因为它们构成了JSON数据与Java对象之间双向转换的“黄金三角”。toJSONString负责“出去”序列化parseObject和parseArray负责“进来”反序列化。几乎所有涉及外部系统交互如调用HTTP API、读取配置文件、处理消息队列数据的场景都绕不开它们。但问题恰恰在于很多人只记住了“怎么用”却忽略了“为什么这么用”以及“什么时候不能这么用”。比如面对一个复杂的嵌套JSON你是该用parseObject一次解析完还是分层逐步解析面对一个超大的JSON数组直接用parseArray会不会把内存撑爆把一个包含敏感信息的对象用toJSONString默认序列化出去会不会导致数据泄露接下来我不会仅仅重复API文档而是会结合真实的踩坑案例带你重新认识这三个方法。我们会从最基础的用法开始逐步深入到定制化序列化、性能优化、安全考量等高级话题。无论你是刚刚接触JSON处理的初学者还是想巩固细节的资深开发者相信都能从中获得一些新的启发和实用的“避坑指南”。2. 基础拆解三个方法的定位与核心用法在深入细节之前我们必须先统一认知这里讨论的JSON类通常指的是com.alibaba.fastjson.JSON。它是Fastjson库的入口类。其他库如Jackson的ObjectMapperGson的Gson类其核心思想相通但API设计略有不同。本部分内容以Fastjson为例但原理适用于所有JSON库。2.1 JSON.toJSONString()对象到字符串的“编码器”这个方法的作用是将一个Java对象Object转换序列化成JSON格式的字符串。这是数据“走出去”的第一步无论是写入文件、发送HTTP请求还是存入数据库通常都需要这一步。最基本的用法非常简单User user new User(张三, 30); String jsonString JSON.toJSONString(user); System.out.println(jsonString); // 输出{age:30,name:张三}这里User对象的name和age属性被转换成了JSON的键值对。默认情况下Fastjson使用属性名通过getter方法推断作为JSON的key并且key的顺序是不确定的取决于Java反射获取字段的顺序实践中常按字母序排序。但“基础用法”往往隐藏着第一个坑默认序列化会暴露所有getter方法对应的属性。假设你的User类还有一个getPassword()方法即使用于内部传输的password字段本身是私有的它也会被序列化到JSON字符串里public class User { private String name; private int age; private String password; // ... 构造方法和其他getter/setter public String getPassword() { return password; } } User user new User(张三, 30, 123456); String jsonString JSON.toJSONString(user); // 输出可能包含{age:30,name:张三,password:123456}这无疑是严重的安全隐患。因此第一个实战经验永远不要依赖默认序列化来处理包含敏感信息的对象。我们会在后面的章节详细讲解如何通过注解或自定义序列化器来控制输出。2.2 JSON.parseObject()字符串到单个对象的“解码器”这个方法是toJSONString的逆过程它将一个JSON格式的字符串解析并填充到一个指定的Java类实例中。典型用法如下String jsonStr {\name\:\李四\,\age\:25}; User user JSON.parseObject(jsonStr, User.class); System.out.println(user.getName()); // 输出李四这个过程叫做反序列化。Fastjson会通过反射找到User.class中与JSON key同名的属性或通过setter方法并将对应的值设置进去。这里会遇到第二个常见坑JSON结构与Java类结构不匹配。这又细分为几种情况多余字段JSON有Java类没有默认情况下Fastjson会忽略这些多余的键值对。这通常是安全的但如果你需要严格校验则需要额外配置。缺失字段Java类有JSON没有该字段在Java对象中会被设置为默认值对象为null基本类型为0/false等。这可能导致业务逻辑错误比如一个必需的id字段为null。类型不匹配JSON中的数字“123”字符串类型试图赋值给Java的int类型字段Fastjson会尝试智能转换。大部分基础类型转换它能处理但复杂转换如日期字符串“2023-01-01”到Date对象就需要特定的格式或自定义反序列化器。因此第二个实战经验对于重要的反序列化操作不要假设数据一定是完美的。应考虑使用Feature进行严格模式校验或在使用前对反序列化后的对象进行有效性验证。2.3 JSON.parseArray()字符串到对象列表的“批量解码器”当JSON字符串的根结构是一个数组即以[开头]结尾时就需要使用parseArray。它可以将一个包含多个JSON对象的数组字符串转换为一个ListT。用法示例String jsonArrayStr [{\name\:\王五\,\age\:28}, {\name\:\赵六\,\age\:35}]; ListUser userList JSON.parseArray(jsonArrayStr, User.class); for (User u : userList) { System.out.println(u.getName()); } // 输出 // 王五 // 赵六从功能上看你可以理解为parseArray在内部循环调用了parseObject。但它一次性处理了整个数组并返回一个完整的List。这就引出了第三个也是影响最大的一个坑大JSON数组的内存与性能问题。parseArray会一次性将整个JSON数组解析到内存中并生成一个包含所有对象的List。如果这个数组非常大比如几十万条记录那么会瞬间消耗大量JVM堆内存可能直接导致OutOfMemoryError。对于这种场景绝对不要使用parseArray。解决方案是使用流式解析如Jackson的JsonParser或Fastjson的JSONReader逐个读取和处理数组中的元素我们会在第5章详细讨论。3. 进阶应用定制化序列化与反序列化掌握了基础用法我们来看看如何“驯服”这三个方法让它们按照我们的意愿工作。这主要通过注解和配置SerializerFeature/Feature来实现。3.1 使用注解精细控制字段行为Fastjson提供了一系列注解可以直接标注在Java类的字段或getter/setter方法上以影响序列化和反序列化行为。JSONField这是最强大、最常用的注解。name: 指定序列化后的字段名。例如JSONField(name “user_name”)Java字段userName在JSON中会变成“user_name”。这在对接字段命名风格不同的外部API时非常有用。format: 主要用于日期字段。例如JSONField(format “yyyy-MM-dd HH:mm:ss”)可以统一日期格式的输入输出。serialize/deserialize: 控制是否参与序列化或反序列化。这是解决前面提到的敏感字段泄露问题的关键。你可以给password字段的getter方法加上JSONField(serialize false)这样它就不会被序列化到JSON字符串中。ordinal: 指定字段序列化时的顺序可以用于保证输出JSON的键顺序稳定。public class User { JSONField(name “full_name”, ordinal 1) private String name; JSONField(ordinal 2) private int age; JSONField(serialize false) // 不序列化到JSON private String password; JSONField(format “yyyy-MM-dd”) private Date birthday; // getters and setters ... }JSONType类级别的注解可以配置序列化/反序列化的忽略字段、排序方式、包含字段的策略等。JSONType(ignores {“internalCode”, “secretKey”}) // 忽略这两个字段 public class ApiResponse { // ... }3.2 利用SerializerFeature和Feature进行全局配置除了注解还可以在调用方法时传入特性Feature参数进行更灵活的全局控制。对于toJSONString使用SerializerFeatureUser user new User(“张三”, 30); // 美化输出PrettyFormat String prettyJson JSON.toJSONString(user, SerializerFeature.PrettyFormat); // 输出带缩进和换行的JSON便于阅读和调试。 // 输出空值字段WriteMapNullValue user.setName(null); String jsonWithNull JSON.toJSONString(user, SerializerFeature.WriteMapNullValue); // 输出{“age”:30,“name”:null}默认情况下null字段会被忽略。 // 按字段名称排序SortField String sortedJson JSON.toJSONString(user, SerializerFeature.SortField); // 保证输出的JSON键按字母顺序排列这在生成签名或对比JSON时很有用。 // 组合使用多个特性 String result JSON.toJSONString(user, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat);对于parseObject和parseArray使用FeatureString jsonStr “{\name\:\Tom\, \extraField\:\ignoreMe\}”; // 严格模式遇到未知字段Java类不存在的字段时抛出异常 try { User user JSON.parseObject(jsonStr, User.class, Feature.ErrorOnUnknownProperties); } catch (Exception e) { // 会抛出JSONException因为extraField在User类中不存在 System.out.println(“发现未知字段”); } // 非严格模式默认忽略未知字段 User user JSON.parseObject(jsonStr, User.class); // 正常解析extraField被忽略 // 支持自动类型识别AutoTypeSupport—— 高危特性慎用 // Feature.SupportAutoType 允许在JSON中通过type指定类名进行反序列化。 // 这是Fastjson历史上多个高危安全漏洞的根源除非在绝对可信的环境否则强烈不建议开启。第三个实战经验关于日期格式的“坑中坑”。日期处理是JSON序列化中最容易出问题的地方之一。不同的系统、不同的库对日期的默认格式可能不同。我强烈建议在序列化时明确指定日期格式。可以使用JSONField(format“...”)注解或者在toJSONString时使用SerializerFeature.WriteDateUseDateFormat它会使用JSON.DEFFAULT_DATE_FORMAT默认为“yyyy-MM-dd HH:mm:ss”。在反序列化时如果JSON中的日期是字符串也要确保格式匹配或者使用JSONField注解指定格式。否则会解析失败。对于前后端交互一个常见的约定是使用时间戳long类型来传递日期这样可以完全避免格式问题。4. 性能与安全生产环境必须考虑的维度当你的应用从Demo走向生产面对海量数据和高并发请求时性能和安全性就从“加分项”变成了“必选项”。这三个基础方法在这里同样有诸多讲究。4.1 性能优化要点避免重复创建JSON实例/配置对象对于Gson的Gson实例或Jackson的ObjectMapper它们是线程安全的应该创建单例重复使用。反复创建这些重量级对象内部包含缓存、配置等会带来不必要的开销。Fastjson的静态方法本身是线程安全的无需此虑。大JSON数组必须使用流式解析这是最重要的性能优化点。如前所述parseArray会一次性加载所有数据。错误示范内存杀手String hugeJsonArray readFromHugeFile(); // 一个几百MB的JSON数组文件 ListMyData list JSON.parseArray(hugeJsonArray, MyData.class); // 可能导致OOM正确做法使用流式API Fastjson提供了JSONReaderJackson提供了JsonParserGson提供了JsonReader。以Fastjson为例try (JSONReader reader new JSONReader(new FileReader(“huge.json”))) { reader.startArray(); // 读取数组开始符‘[’ while (reader.hasNext()) { MyData data reader.readObject(MyData.class); // 逐个读取对象 process(data); // 处理单个对象然后可以丢弃 } reader.endArray(); // 读取数组结束符‘]’ }这种方式内存占用是常数级的只与单个对象的大小有关非常适合处理数据流或大文件。选择合适的库与版本在微服务架构下序列化性能直接影响RPC框架的效率。根据场景选择Fastjson在已知的基准测试中Fastjson的序列化/反序列化速度通常较快但安全历史记录较差需要谨慎评估和及时升级。Jackson功能全面、社区活跃、生态强大性能优秀是Spring Boot的默认选择安全记录相对较好。Gson由Google开发API简洁与Google服务集成好但性能在某些场景下略逊于前两者。建议对于新项目Spring Boot生态内优先使用Jackson如果对极致性能有要求且能控制数据源安全可考虑Fastjson务必使用最新安全版本Android开发或需要轻量级集成时Gson是个好选择。4.2 安全红线与最佳实践JSON反序列化是远程代码执行RCE漏洞的高发区必须慎之又慎。绝对禁止开启AutoTypeFastjsonFeature.SupportAutoType或ParserConfig.getGlobalInstance().setAutoTypeSupport(true);会允许JSON字符串通过“type”指定任意类进行实例化。攻击者可以构造恶意JSON利用项目依赖中的危险类如TemplatesImpl执行任意代码。在任何生产环境中都应确保AutoType处于关闭状态。使用安全白名单如果业务上确实需要多态反序列化根据类型字段创建不同子类对象Fastjson提供了白名单机制。只允许反序列化明确指定的类。ParserConfig config new ParserConfig(); config.addAccept(“com.yourcompany.model.”); // 只接受指定包下的类 config.addAccept(“com.legitlibrary.”); // 然后使用这个config进行解析 User user JSON.parseObject(jsonStr, User.class, config);验证输入数据不要信任任何外部输入的JSON数据。在反序列化前可以进行基本的格式校验、大小限制等。反序列化后要对对象的业务关键字段进行有效性校验非空、范围、格式等。及时更新依赖关注你使用的JSON库的安全公告及时升级到修复了已知漏洞的版本。这在Fastjson的历史上尤为重要。第四个实战经验建立团队的JSON处理规范。在项目启动时就应该明确本项目使用哪个JSON库版本号锁定为多少日期、金额等通用字段的格式标准是什么是否允许反序列化未知字段默认是忽略还是报错如何统一处理敏感字段的序列化推荐使用注解JSONField(serializefalse)大文件/数据流处理必须使用流式API。禁止在代码中随意开启AutoType等危险特性。 将这些规范写入开发手册或代码模板能有效避免很多潜在问题。5. 实战场景深度剖析与避坑指南理论说再多不如看几个真实的“车祸现场”。下面我结合几个典型场景带你看看这些方法用不好会出什么问题以及正确的姿势是什么。5.1 场景一多层嵌套JSON与泛型的“类型擦除”陷阱假设你有一个复杂的API响应结构如下{ “code”: 0, “message”: “success”, “data”: { “pageNum”: 1, “pageSize”: 10, “total”: 100, “list”: [ {“id”: 1, “title”: “文章1”}, {“id”: 2, “title”: “文章2”} ] } }你定义了对应的Java类public class ApiResponseT { private int code; private String message; private T data; // getters/setters... } public class PageResultL { private int pageNum; private int pageSize; private long total; private ListL list; // getters/setters... } public class Article { private Long id; private String title; // getters/setters... }现在你想把JSON字符串解析成ApiResponsePageResultArticle类型。错误做法String jsonStr ...; // 上面的JSON字符串 ApiResponse response JSON.parseObject(jsonStr, ApiResponse.class); PageResult page (PageResult) response.getData(); List list page.getList(); // 这里的list是ListLinkedHashMap不是ListArticle for (Object o : list) { // 需要强制转换或者处理Map }由于Java泛型的类型擦除parseObject在运行时无法知道T和L的具体类型所以data会被反序列化为LinkedHashMaplist会被反序列化为ListLinkedHashMap。正确做法使用TypeReferenceFastjson/Jackson或TypeTokenGson保留泛型信息。// Fastjson 写法 import com.alibaba.fastjson.TypeReference; String jsonStr ...; ApiResponsePageResultArticle response JSON.parseObject( jsonStr, new TypeReferenceApiResponsePageResultArticle() {} ); // 此时response.getData() 是 PageResultArticle // response.getData().getList() 是 ListArticle ListArticle articles response.getData().getList();TypeReference通过创建一个匿名子类在运行时捕获了完整的泛型类型信息从而指导反序列化器正确地构造出Article对象。5.2 场景二循环引用与栈溢出这是对象关系映射ORM中常见的问题。比如两个对象互相引用public class Department { private String name; private ListEmployee employees; // getters/setters... } public class Employee { private String name; private Department department; // 引用所属部门 // getters/setters... }当你序列化一个Department对象时它会序列化employees列表列表里的每个Employee又会去序列化它的department属性而这个department又指向最初的那个对象从而形成无限循环最终导致StackOverflowError。错误信息可能类似于java.lang.StackOverflowError: null at com.alibaba.fastjson.serializer...解决方案使用JSONField(serialize false)在循环引用的一侧比如Employee的department字段上加上该注解打断循环。使用SerializerFeature.DisableCircularReferenceDetect这个特性会禁用Fastjson的循环引用检测。但这不是一个好主意因为它可能导致前面说的栈溢出或者生成一个无限嵌套的JSON浏览器会解析失败。使用SerializerFeature.WriteMapNullValue配合JSONField(serialize false)更常见的做法是在序列化时忽略反向引用如Employee.department同时在需要展示关联对象ID时可以添加一个只读的departmentId字段。public class Employee { private String name; JSONField(serialize false) // 序列化时忽略 private Department department; // 添加一个只获取ID的getter方法用于序列化 public Long getDepartmentId() { return department ! null ? department.getId() : null; } // getters/setters... }5.3 场景三枚举Enum处理的兼容性问题枚举在JSON序列化中默认使用name()方法即枚举常量的名称。但这可能带来前后端兼容问题。public enum Status { OPEN, CLOSED, PENDING } Status s Status.OPEN; String json JSON.toJSONString(s); // 输出: “OPEN”如果后端枚举值从OPEN改成了OPENED那么历史JSON数据“OPEN”将无法反序列化。或者前端希望传递小写的“open”。解决方案使用JSONField注解指定序列化/反序列化的值public enum Status { JSONField(name “open”) OPEN, JSONField(name “closed”) CLOSED; } // 序列化Status.OPEN得到“open”反序列化“open”得到Status.OPEN自定义枚举的序列化/反序列化逻辑实现ObjectSerializer和ObjectDeserializer接口进行更复杂的映射例如与数据库code值对应。第五个实战经验为枚举类型建立稳定的“契约”。在设计枚举时就应确定其对外暴露的值可以是name也可以是自定义的code并尽量保持不变。如果必须变更需要考虑数据迁移和接口版本兼容方案。6. 框架集成与生态工具在实际项目中我们很少直接裸调JSON.parseObject而是通过Spring Boot等框架间接使用。了解框架的集成方式能让你更好地定位和解决问题。6.1 在Spring Boot中配置JSON处理器Spring Boot默认使用Jackson。如果你想替换为Fastjson或Gson需要排除默认的Jackson依赖并引入新依赖以Fastjson为例dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId exclusions exclusion groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-json/artifactId /exclusion /exclusions /dependency dependency groupIdcom.alibaba/groupId artifactIdfastjson/artifactId version2.0.42/version !-- 务必使用安全的最新版本 -- /dependency配置HttpMessageConverter通过一个Configuration类注册Fastjson的转换器。Configuration public class FastjsonConfig { Bean public HttpMessageConverter? fastJsonHttpMessageConverter() { FastJsonHttpMessageConverter converter new FastJsonHttpMessageConverter(); FastJsonConfig config new FastJsonConfig(); config.setSerializerFeatures( SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat ); config.setCharset(StandardCharsets.UTF_8); // 安全配置关闭AutoType config.getParserConfig().setAutoTypeSupport(false); // 可以设置白名单 // config.getParserConfig().addAccept(“com.yourpackage.”); converter.setFastJsonConfig(config); converter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON)); return converter; } }完成配置后Controller中RequestBody和ResponseBody的序列化/反序列化就会通过Fastjson进行。6.2 常用工具与在线校验除了核心的转换方法还有一些周边工具能极大提升效率IDE插件如IntelliJ IDEA的“JSON Parser”或VS Code的“JSON Tools”可以快速格式化、压缩、验证JSON字符串。在线校验与格式化网站如 json.cn、jsonformatter.org。在联调接口时将复杂的JSON粘贴过去格式化一下结构一目了然。浏览器插件如“JSON Viewer”自动将浏览器中返回的JSON数据以树形结构美观地展示。命令行工具jq在Linux/Mac环境下jq是处理和分析JSON数据的瑞士军刀可以用于过滤、映射、转换等复杂操作。6.3 日志中的JSON美化在开发调试时我们经常需要打印对象。直接打印toString()或者用默认的toJSONString()日志会挤在一行难以阅读。log.info(“Response: {}”, JSON.toJSONString(response)); // 输出Response: {“code”:0,“data”:{“list”:[...]...}}一个小技巧在开发或测试环境的日志配置中可以全局配置SerializerFeature.PrettyFormat或者更精细地在需要调试的地方临时使用log.info(“Response:\n{}”, JSON.toJSONString(response, SerializerFeature.PrettyFormat));这样日志会以结构化的缩进格式输出排查数据问题时非常方便。当然在生产环境要关掉避免产生不必要的日志量。7. 从原理理解行为为什么会有这些“坑”要真正避免踩坑不能只记“怎么做”还要理解“为什么”。让我们稍微深入一点看看这些方法背后的基本原理。序列化toJSONString的本质是将内存中的对象图Object Graph转换编码成一种与语言无关、便于传输或存储的文本格式JSON字符串。这个过程主要涉及反射通过反射获取对象的类信息、字段、方法。类型推断与转换将Java的int、long、Date、List等类型映射为JSON的number、string、array等类型。递归遍历如果对象属性是另一个对象或集合则需要递归地进行上述过程。这正是循环引用导致栈溢出的根源。字符串拼接最终将所有键值对组装成符合JSON语法的字符串。高性能的库如Fastjson会使用StringBuilder或直接操作字符数组来优化这一过程。反序列化parseObject/parseArray的本质是序列化的逆过程将JSON字符串“解码”并重建为内存中的Java对象。这个过程主要涉及词法分析Lexing将字符串分解成一个个有意义的令牌Token如{、}、“name”、:、“张三”。语法分析Parsing根据JSON语法规则将令牌组织成树状结构AST抽象语法树。对象构造与填充根据目标类型User.class通过反射创建实例然后遍历AST将对应的值通过setter方法或直接字段赋值取决于配置填充到对象中。类型转换将JSON字符串中的值如“123”转换为Java字段的类型如int。理解了这些你就能明白为什么大JSON数组会耗内存因为语法分析阶段第2步通常需要先将整个字符串加载到内存中构建ASTparseArray随后会一次性将AST的所有节点转换为Java对象并装入一个List。为什么循环引用会栈溢出因为在序列化的递归遍历第3步中没有终止条件调用栈会不断加深直至耗尽。为什么泛型信息会丢失因为Java的泛型是编译期的“语法糖”在编译后字节码中会被擦除替换为原始类型Raw Type或边界类型。运行时反射API第3步无法获取ListT中T的具体类型所以只能默认用Map或Object来装。第六个实战经验将原理作为调试的指南针。当遇到奇怪的序列化/反序列化问题时别急着瞎试。按照上述流程思考现在是序列化还是反序列化出问题问题发生在哪个阶段是反射找不到字段还是类型转换失败是递归深度太大还是内存不足有了方向再结合错误信息和调试工具如断点查看中间状态就能快速定位根因。8. 替代方案与未来展望虽然JSON.parseArray/Object/toJSONString是Java生态中最常见的JSON处理方式但了解其他方案能让你在特定场景下做出更优选择。1. 其他序列化格式Protocol Buffers (protobuf) / Apache Thrift / Apache Avro这些都是二进制序列化框架。与JSON相比它们生成的字节流体积更小、序列化/反序列化速度更快、并且有严格的模式Schema定义能提供更好的前后向兼容性。适用于对性能、带宽要求极高的内部服务间RPC通信。缺点是可读性差需要预编译生成代码。MessagePack类似于JSON但也是二进制的。它算是JSON的一种二进制扩展在保持一定可读性的同时比JSON更紧凑、更快。适合做缓存或网络传输。YAML / TOML这两种是更注重人类可读性的配置格式。在配置文件领域如Spring Boot的application.yml比JSON更流行。它们通常不适合做高频的网络数据传输。2. 无模式Schema-less与强模式Schema的权衡JSON属于“无模式”或“读时模式”Schema-on-Read。它的结构是灵活的但这也意味着消费方必须知道数据的确切结构或者编写复杂的兼容性逻辑。而像protobuf这样的“写时模式”Schema-on-Write或“强模式”在定义.proto文件时就约定了数据结构任何不符合模式的写入都会被拒绝这保证了数据的一致性和质量。对于大型、长期演进的系统强模式带来的契约优势越来越被重视。3. 未来趋势JSON Schema与代码生成即使使用JSON也可以引入JSON Schema来定义数据结构的契约。你可以用JSON Schema描述一个API接口请求/响应的格式然后用于文档化比口头约定可靠。用于在线验证在Swagger UI等工具中。通过工具自动生成不同语言的DTO类如使用jsonschema2pojo。这能减少手动编写POJO的工作量并保证代码与契约的一致性。在我个人的项目经验中技术选型没有银弹。我的习惯是对外公开的HTTP API优先使用JSON因为它是Web领域的通用语调试、文档化、跨语言支持都最好。同时可以考虑提供OpenAPISwagger描述和JSON Schema。内部高性能RPC优先考虑protobuf或gRPC基于protobuf。配置文件使用YAMLSpring Boot或TOMLRust生态。缓存或消息队列中的中间数据根据序列化/反序列化的性能需求和可调试性权衡JSON和MessagePack都是可选方案。说到底JSON.parseArray、parseObject和toJSONString这三个方法是你作为Java开发者处理数据交换的基石工具。把它们用对、用熟、用透意味着你能高效可靠地完成大多数数据对接任务。而理解其背后的原理、陷阱和最佳实践则能让你在遇到复杂问题时从容应对写出既健壮又高性能的代码。希望这篇长文能成为你手边的一份实用参考下次再遇到JSON相关的问题时能少走些弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价