You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 04:52:14