Gson序列化Kotlin的Arena类时触发InaccessibleObjectException异常
问题:Gson序列化Kotlin自定义类触发InaccessibleObjectException
报错堆栈
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private java.lang.Object java.lang.ref.Reference.referent accessible: module java.base does not "opens java.lang.ref" to unnamed module @40444e23 at java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354) ~[?:?] at java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297) ~[?:?] at java.lang.reflect.Field.checkCanSetAccessible(Field.java:180) ~[?:?] at java.lang.reflect.Field.setAccessible(Field.java:174) ~[?:?] at com.google.gson.internal.reflect.UnsafeReflectionAccessor.makeAccessible(UnsafeReflectionAccessor.java:44) ~[gson-2.8.9.jar:?] at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:159) ~[gson-2.8.9.jar:?] at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102) ~[gson-2.8.9.jar:?] at com.google.gson.Gson.getAdapter(Gson.java:489) ~[gson-2.8.9.jar:?] at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117) ~[gson-2.8.9.jar:?] at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166) ~[gson-2.8.9.jar:?] at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102) ~[gson-2.8.9.jar:?] at com.google.gson.Gson.getAdapter(Gson.java:489) ~[gson-2.8.9.jar:?] at com.google.gson.internal.bind.CollectionTypeAdapterFactory.create(CollectionTypeAdapterFactory.java:53) ~[gson-2.8.9.jar:?] at com.google.gson.Gson.getAdapter(Gson.java:489) ~[gson-2.8.9.jar:?] at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117) ~[gson-2.8.9.jar:?] at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166) ~[gson-2.8.9.jar:?] at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102) ~[gson-2.8.9.jar:?] at com.google.gson.Gson.getAdapter(Gson.java:489) ~[gson-2.8.9.jar:?] at com.google.gson.Gson.toJson(Gson.java:727) ~[gson-2.8.9.jar:?] at com.google.gson.Gson.toJson(Gson.java:714) ~[gson-2.8.9.jar:?] at com.google.gson.Gson.toJson(Gson.java:669) ~[gson-2.8.9.jar:?] at com.google.gson.Gson.toJson(Gson.java:649) ~[gson-2.8.9.jar:?] at de.carina.pixelsjump.util.arena.Arena.saveArena(Arena.kt:35) ~[PixelsJumpRemastered-1.0.0-all.jar:?] at de.carina.pixelsjump.commands.setup.ArenaFinish.execute(ArenaFinish.kt:53) ~[PixelsJumpRemastered-1.0.0-all.jar:?] at de.carina.pixelsjump.commands.util.CommandRegister.onCommand(CommandRegister.kt:36) ~[PixelsJumpRemastered-1.0.0-all.jar:?] at org.bukkit.command.PluginCommand.execute(PluginCommand.java:45) ~[paper-api-1.19-R0.1-SNAPSHOT.jar:?] ... 26 more Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private java.lang.Object java.lang.ref.Reference.referent accessible: module java.base does not "opens java.lang.ref" to unnamed module @40444e23
待序列化的Arena类代码
class Arena(val name: String) { val checkPoints: MutableList<Location> = mutableListOf() var startLocation: Location? = null var finishLocation: Location? = null var backLocation: Location? = null val players = mutableSetOf<Player>() @Transient private val file: File = File("plugins/PixelsJumpRemastered/arenas/$name.json") var single: Boolean = false var damage: Boolean = false fun saveArena() { val gson = GsonBuilder().setPrettyPrinting().create() var json = gson.toJson(this) file.writeText(json) } fun addCheckpointLocation(location: Location) { checkPoints.add(location.block.getRelative(BlockFace.DOWN).location.toCenterLocation()) } }
解决思路
1. 排除无法序列化的对象(核心修复)
报错根源是Gson尝试序列化players集合中的Player对象,而Player是Bukkit的引用类型,内部包含Reference相关字段,Java 9+的模块系统禁止Gson通过反射访问这些内部字段。
给players字段加上@Transient注解,让Gson跳过序列化:
@Transient val players = mutableSetOf<Player>()
2. 升级Gson版本
当前使用的Gson 2.8.9对Java模块系统兼容性较差,升级到Gson 2.10.1及以上版本,新版本优化了反射访问逻辑,能更好适配Java 9+的模块规则。
3. 为Bukkit类型自定义TypeAdapter
Location这类Bukkit对象默认无法被Gson正确序列化/反序列化,需自定义TypeAdapter实现转换:
class LocationTypeAdapter : TypeAdapter<Location>() { override fun write(out: JsonWriter, value: Location?) { if (value == null) { out.nullValue() return } out.beginObject() out.name("world").value(value.world.name) out.name("x").value(value.x) out.name("y").value(value.y) out.name("z").value(value.z) out.name("yaw").value(value.yaw) out.name("pitch").value(value.pitch) out.endObject() } override fun read(`in`: JsonReader): Location? { `in`.beginObject() var worldName: String? = null var x = 0.0 var y = 0.0 var z = 0.0 var yaw = 0f var pitch = 0f while (`in`.hasNext()) { when (`in`.nextName()) { "world" -> worldName = `in`.nextString() "x" -> x = `in`.nextDouble() "y" -> y = `in`.nextDouble() "z" -> z = `in`.nextDouble() "yaw" -> yaw = `in`.nextFloat() "pitch" -> pitch = `in`.nextFloat() } } `in`.endObject() val world = Bukkit.getWorld(worldName ?: return null) ?: return null return Location(world, x, y, z, yaw, pitch) } }
创建Gson实例时注册该Adapter:
val gson = GsonBuilder() .setPrettyPrinting() .registerTypeAdapter(Location::class.java, LocationTypeAdapter()) .create()
4. JVM参数临时绕过(不推荐)
若以上方案无法快速生效,可添加JVM启动参数临时允许模块反射访问:
--add-opens java.base/java.lang.ref=ALL-UNNAMED
此方案仅作临时应急,会破坏Java模块系统的封装性,不建议长期使用。
内容的提问来源于stack exchange,提问作者Carina Sophie
相关产品推荐
相关产品推荐

