升级Java17+SpringBoot3.1.2+Gson2.10.1时遇InaccessibleObjectException
问题解决方法
1. 添加JVM启动参数开放反射权限
Java 17的模块系统(JPMS)收紧了反射访问私有字段的权限,直接给spring-boot-maven-plugin的pre-integration-test阶段添加JVM参数,开放对应包的反射权限即可:
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>3.1.2</version> <executions> <execution> <id>pre-integration-test</id> <goals> <goal>start</goal> </goals> <configuration> <jvmArguments> --add-opens java.base/java.lang=ALL-UNNAMED </jvmArguments> </configuration> </execution> <!-- 保留你原有其他execution配置 --> </executions> </plugin>
该参数允许未命名模块(你的应用所在模块)访问java.base模块下java.lang包的内部成员,让Gson能合法读取StackTraceElement#classLoaderName字段。
2. 自定义Gson序列化规则规避反射
如果不想开放全局反射权限,可以自定义TypeAdapter,通过StackTraceElement的公开API完成序列化,避免直接访问私有字段:
public class StackTraceElementAdapter extends TypeAdapter<StackTraceElement> { @Override public void write(JsonWriter out, StackTraceElement element) throws IOException { out.beginObject(); out.name("className").value(element.getClassName()); out.name("methodName").value(element.getMethodName()); out.name("fileName").value(element.getFileName()); out.name("lineNumber").value(element.getLineNumber()); out.endObject(); } @Override public StackTraceElement read(JsonReader in) throws IOException { in.beginObject(); String className = null; String methodName = null; String fileName = null; int lineNumber = -1; while (in.hasNext()) { switch (in.nextName()) { case "className": className = in.nextString(); break; case "methodName": methodName = in.nextString(); break; case "fileName": fileName = in.nextString(); break; case "lineNumber": lineNumber = in.nextInt(); break; default: in.skipValue(); } } in.endObject(); return new StackTraceElement(className, methodName, fileName, lineNumber); } }
注册该适配器到Gson实例:
Gson gson = new GsonBuilder() .registerTypeAdapter(StackTraceElement.class, new StackTraceElementAdapter()) .create();
3. 升级Gson至最新兼容版本
尝试将Gson升级到2.10.2及以上稳定版,后续版本针对Java 17的模块系统做了适配优化,可能已经修复了该私有字段反射访问的问题。
内容的提问来源于stack exchange,提问作者Arindam
相关产品推荐
相关产品推荐

