反射赋值ImmutableMap至Map字段报错,求解决方案
Bukkit插件修改PluginDescriptionFile的commands字段报错解决
问题场景
在Bukkit插件开发中,尝试通过反射修改PluginDescriptionFile里的commands字段(初始为ImmutableMap),添加自定义命令别名时抛出类型转换异常。
原代码
Field field = this.getDescription().getClass().getDeclaredField("commands"); Map<String, Map<String, Object>> commands = new HashMap<>(); this.getDescription().getCommands().forEach((c, v) -> commands.put(c, v)); for (String alias : this.aliasManager.getAllAliases()) { Map<String, Object> map = new HashMap<>(); map.put("description", "An alias for " + aliasManager.getAlias(alias).getCommand()); map.put("usage", "/<command>"); map.put("name", alias); commands.put(alias, map); } Map<String, Map<String, Object>> immutableMap = ImmutableMap.copyOf(commands); field.setAccessible(true); field.set(this.getDescription().getCommands(), immutableMap);
报错信息
java.lang.IllegalArgumentException: Can not set java.util.Map field org.bukkit.plugin.PluginDescriptionFile.commands to com.google.common.collect.SingletonImmutableBiMap
字段声明
private Map<String, Map<String, Object>> commands = (Map<String, Map<String, Object>>)ImmutableMap.of();
解决方法
核心错误是反射设置字段时传入的目标对象错误:commands字段属于PluginDescriptionFile实例,而非getCommands()返回的Map对象。修正代码如下:
Field field = this.getDescription().getClass().getDeclaredField("commands"); Map<String, Map<String, Object>> commands = new HashMap<>(); // 复制原有命令到新Map this.getDescription().getCommands().forEach(commands::put); // 添加自定义别名命令 for (String alias : this.aliasManager.getAllAliases()) { Map<String, Object> map = new HashMap<>(); map.put("description", "An alias for " + aliasManager.getAlias(alias).getCommand()); map.put("usage", "/<command>"); map.put("name", alias); commands.put(alias, map); } // 可选择转为ImmutableMap(保持原字段特性),或直接使用HashMap Map<String, Map<String, Object>> targetMap = ImmutableMap.copyOf(commands); field.setAccessible(true); // 关键:传入PluginDescriptionFile实例作为字段所属对象 field.set(this.getDescription(), targetMap);
错误原因说明
原代码中field.set(this.getDescription().getCommands(), immutableMap)是错误的:
field是PluginDescriptionFile类的成员字段,必须传入PluginDescriptionFile实例作为第一个参数,才能修改该实例的字段值。- 之前传入的
getCommands()返回的Map对象,并非字段所属的实例,JVM无法将ImmutableMap赋值给不属于它的字段,因此抛出类型不匹配异常。
另外,字段声明为Map接口,无论是ImmutableMap还是HashMap都符合类型要求,无需担心类型兼容问题,只要目标实例传对即可。
内容的提问来源于stack exchange,提问作者Gargant
相关产品推荐
相关产品推荐

