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

使用Gson将POJO转为Json字符串时遇权限错误(Java19)

Java 19下Gson序列化POJO遇ThreadLocal字段访问错误的解决办法

问题本质

Java 19的模块系统进一步收紧了反射访问权限,Gson默认通过反射序列化对象时,会尝试访问java.lang.ThreadLocal的私有字段threadLocalHashCode,但该字段并未向未命名模块开放访问权限,因此抛出无法访问的错误。

解决方法

1. 升级Gson到兼容版本

Gson 2.10及以上版本已针对Java 9+的模块系统做了适配,修复了此类反射权限问题。直接升级依赖即可:

<!-- Maven依赖示例 -->
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.10.1</version>
</dependency>

2. 添加JVM启动参数开放权限

如果暂时无法升级Gson,可在启动Java程序时添加以下参数,允许未命名模块访问java.lang包的内部字段:

--add-opens java.base/java.lang=ALL-UNNAMED

3. 自定义TypeAdapter控制序列化逻辑

如果你的PlayerModel类中包含ThreadLocal类型的字段,可通过自定义TypeAdapter避免Gson默认的反射处理,手动控制序列化/反序列化行为。

示例代码

假设你的PlayerModel类结构如下:

public class PlayerModel {
    private String name;
    private int level;
    private ThreadLocal<String> sessionId;

    // 构造器、Getter、Setter
    public PlayerModel(String name, int level, ThreadLocal<String> sessionId) {
        this.name = name;
        this.level = level;
        this.sessionId = sessionId;
    }

    public String getName() { return name; }
    public int getLevel() { return level; }
    public ThreadLocal<String> getSessionId() { return sessionId; }
}
自定义ThreadLocalTypeAdapter
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;

public class ThreadLocalTypeAdapter extends TypeAdapter<ThreadLocal<?>> {
    @Override
    public void write(JsonWriter out, ThreadLocal<?> value) throws IOException {
        // 序列化时仅写入当前线程绑定的实际值
        out.value(value.get().toString());
    }

    @Override
    public ThreadLocal<?> read(JsonReader in) throws IOException {
        // 反序列化时创建新的ThreadLocal并绑定值
        ThreadLocal<String> threadLocal = new ThreadLocal<>();
        threadLocal.set(in.nextString());
        return threadLocal;
    }
}
注册TypeAdapter并使用
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class SerializationDemo {
    public static void main(String[] args) {
        ThreadLocal<String> sessionId = ThreadLocal.withInitial(() -> "SESSION-789");
        PlayerModel player = new PlayerModel("Bob", 35, sessionId);

        // 注册自定义TypeAdapter到Gson
        Gson gson = new GsonBuilder()
                .registerTypeAdapter(ThreadLocal.class, new ThreadLocalTypeAdapter())
                .create();

        // 序列化
        String jsonStr = gson.toJson(player);
        System.out.println("序列化结果:" + jsonStr);

        // 反序列化
        PlayerModel restoredPlayer = gson.fromJson(jsonStr, PlayerModel.class);
        System.out.println("反序列化后sessionId:" + restoredPlayer.getSessionId().get());
    }
}

关于Jackson的补充问题

你提到使用Jackson也出现错误,大概率也是模块权限问题。可添加相同的JVM启动参数--add-opens java.base/java.lang=ALL-UNNAMED,或升级Jackson到最新兼容版本(2.15+)。

内容的提问来源于stack exchange,提问作者Moisés Zambrano

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 15:25:24