使用Gson序列化含LocalDateTime的类时出现Java反射访问错误
问题原因
这不是Gson的问题,是Java 9+模块系统的权限限制导致的。Gson默认通过反射访问LocalDateTime的私有字段(比如date),但java.base模块未将java.time包开放给你的代码所在的未命名模块,因此抛出InaccessibleObjectException。
解决方案
以下三种方案按推荐程度排序:
1. 使用Gson官方Java 8时间扩展模块
这是最规范的方案,无需绕开模块权限限制:
- 添加Gson Java 8扩展依赖(以Maven为例,版本需与你的Gson主版本一致):
<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson-java8</artifactId> <version>2.10.1</version> </dependency> - 创建Gson实例时注册
JavaTimeModule,它会自动处理LocalDateTime等Java 8时间类型:
序列化后的Gson gson = new GsonBuilder() .registerModule(new JavaTimeModule()) .create();LocalDateTime会以ISO-8601格式字符串输出,同时避免了反射访问私有字段的问题。
2. 添加JVM启动参数开放模块权限
如果不想引入额外依赖,可通过JVM参数放宽模块访问限制:
- 精准开放
java.time包给未命名模块(推荐,安全性更高):--add-opens java.base/java.time=ALL-UNNAMED - 全局放宽非法访问限制(不推荐,安全性低):
-Djdk.module.illegalAccess=permit
3. 自定义TypeAdapter处理LocalDateTime
自行实现序列化/反序列化逻辑,完全避免反射:
public class LocalDateTimeAdapter extends TypeAdapter<LocalDateTime> { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME; @Override public void write(JsonWriter out, LocalDateTime value) throws IOException { if (value == null) { out.nullValue(); return; } out.value(FORMATTER.format(value)); } @Override public LocalDateTime read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null; } return LocalDateTime.parse(in.nextString(), FORMATTER); } }
注册到GsonBuilder:
Gson gson = new GsonBuilder() .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeAdapter()) .create();
内容的提问来源于stack exchange,提问作者Amsal N
相关产品推荐
相关产品推荐

