Java中使用JSON库格式化大JSON数组时数据丢失问题求助
解决大JSON格式化时的数据丢失与Java 19下Gson兼容问题
一、格式化后数据丢失(org.json/Jackson)
核心原因
绝大多数情况是原JSON存在重复键,org.json的JSONObject和Jackson默认配置都会自动覆盖重复的键值对,导致原始数据被丢弃,最终输出体积大幅缩小。此外,若原JSON存在未正确转义的特殊字符,也可能导致解析时截断数据。
修复方案
1. 排查重复键(Jackson)
先配置Jackson检测重复键,快速定位问题位置:
ObjectMapper mapper = new ObjectMapper(); // 开启重复键报错,直接定位问题键名 mapper.enable(DeserializationFeature.FAIL_ON_READING_DUPLICATE_KEYS); try { JsonNode tree = mapper.readTree(json); json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(tree); } catch (JsonProcessingException e) { e.printStackTrace(); }
2. 流式处理保留所有原始数据
对于10MB级的大JSON,推荐使用流式API,既避免内存溢出,又能完整保留所有原始内容(包括重复键):
Jackson流式实现
StringWriter writer = new StringWriter(); JsonFactory factory = new JsonFactory(); try (JsonParser parser = factory.createParser(json); JsonGenerator generator = factory.createGenerator(writer)) { generator.setPrettyPrinter(new DefaultPrettyPrinter()); // 逐事件复制,完全保留原始JSON结构 while (parser.nextToken() != null) { generator.copyCurrentEvent(parser); } } catch (IOException e) { e.printStackTrace(); } json = writer.toString();
org.json替代方案
org.json本身不支持保留重复键,建议直接替换为Jackson流式处理(自定义JSONObject实现复杂度高,不推荐)。
二、Java 19下Gson反射权限报错
核心原因
Java 19加强了模块反射访问限制,旧版本Gson(≤2.9.1)尝试访问java.io.Reader#lock私有字段时触发权限拦截。
修复方案
1. 升级Gson到最新版本
直接升级Gson至2.10.1及以上,新版本已适配Java 19+的模块权限规则,无需额外配置:
<!-- Maven依赖示例 --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.10.1</version> </dependency>
2. 添加VM权限参数(无法升级时)
在JVM启动参数中添加,开放java.io模块的反射权限:
--add-opens java.base/java.io=ALL-UNNAMED
3. Gson流式处理(无依赖升级/权限修改)
使用Gson的流式API直接复制JSON事件,绕过反射解析逻辑:
Gson gson = new GsonBuilder().setPrettyPrinting().create(); StringWriter writer = new StringWriter(); try (JsonReader reader = new JsonReader(new StringReader(json)); JsonWriter jsonWriter = gson.newJsonWriter(writer)) { jsonWriter.setIndent(" "); JsonToken token; while ((token = reader.peek()) != JsonToken.END_DOCUMENT) { switch (token) { case BEGIN_ARRAY: reader.beginArray(); jsonWriter.beginArray(); break; case END_ARRAY: reader.endArray(); jsonWriter.endArray(); break; case BEGIN_OBJECT: reader.beginObject(); jsonWriter.beginObject(); break; case END_OBJECT: reader.endObject(); jsonWriter.endObject(); break; case NAME: jsonWriter.name(reader.nextName()); break; case STRING: jsonWriter.value(reader.nextString()); break; case NUMBER: jsonWriter.value(reader.nextDouble()); break; case BOOLEAN: jsonWriter.value(reader.nextBoolean()); break; case NULL: reader.nextNull(); jsonWriter.nullValue(); break; } } } catch (IOException e) { e.printStackTrace(); } json = writer.toString();
内容的提问来源于stack exchange,提问作者BullyWiiPlaza
相关产品推荐
相关产品推荐

