使用Gson的fromJson()触发IllegalArgumentException问题求助
解决Gson解析时"declares multiple JSON fields named hash"异常的方案
这个异常的根源很明确:你的Event类继承了JavaFX的EventHandler,而Gson默认会序列化所有继承层级中的字段——包括JavaFX内部类(比如HighlightRegion)里的字段,刚好这些内部类和你的继承链里有同名的hash字段,导致Gson无法处理字段冲突。
结合你的场景(解析包含Event成员的Quest对象),给你几个可行的解决方向:
1. 用Gson的排除策略过滤不必要的字段
你可以通过ExclusionStrategy告诉Gson忽略JavaFX相关的父类字段,或者直接排除冲突的hash字段。
示例代码:
修改parseQuest方法里的Gson初始化逻辑:
Gson gson = new GsonBuilder() .setExclusionStrategies(new ExclusionStrategy() { @Override public boolean shouldSkipField(FieldAttributes f) { // 直接排除名为hash的字段,或者过滤javafx包下的类的字段 return f.getName().equals("hash") || f.getDeclaringClass().getPackageName().startsWith("javafx."); } @Override public boolean shouldSkipClass(Class<?> clazz) { // 忽略所有javafx包下的类的序列化 return clazz.getPackageName().startsWith("javafx."); } }) .create();
2. 使用@Expose注解指定仅序列化自定义字段
只在你自己定义的Event类字段上添加@Expose注解,然后让Gson只序列化带有该注解的字段,自动忽略继承来的JavaFX字段。
步骤:
- 修改
Event类的字段:
import com.google.gson.annotations.Expose; public abstract class Event implements EventHandler<ActionEvent> { @Expose private String title, text; @Expose private Button[] buttonSet; @Expose protected Entity other; @Expose protected Event nextEvent; // 原有方法逻辑不变 }
- 初始化Gson时启用注解过滤:
Gson gson = new GsonBuilder() .excludeFieldsWithoutExposeAnnotation() .create();
3. 重构类结构:用组合代替继承
如果允许修改类设计,建议不要让Event直接继承EventHandler,而是用组合的方式封装事件处理逻辑。这样可以彻底避免Gson序列化JavaFX父类字段的问题。
示例思路:
public abstract class Event { // 你的自定义字段 private String title, text; private Button[] buttonSet; protected Entity other; protected Event nextEvent; // 封装EventHandler逻辑 public EventHandler<ActionEvent> getEventHandler() { return event -> { String command = ((Button) event.getSource()).getText(); displayNewEvent(chooseNewEvent(command)); }; } public abstract Event chooseNewEvent(String command); protected abstract void displayNewEvent(Event event); }
之后在使用按钮时,调用event.getEventHandler()来绑定事件即可。
4. 自定义TypeAdapter手动控制序列化
如果需要更精细的控制,可以为Event类编写自定义的TypeAdapter,手动指定要序列化/反序列化的字段,完全忽略继承来的内容。
简化示例:
class EventTypeAdapter extends TypeAdapter<Event> { @Override public void write(JsonWriter out, Event value) throws IOException { out.beginObject(); out.name("title").value(value.title); out.name("text").value(value.text); // 手动写入其他需要的字段 out.endObject(); } @Override public Event read(JsonReader in) throws IOException { // 根据JSON内容手动构建Event对象,这里需要根据你的具体实现调整 in.beginObject(); String title = null; String text = null; while (in.hasNext()) { switch (in.nextName()) { case "title": title = in.nextString(); break; case "text": text = in.nextString(); break; // 处理其他字段 default: in.skipValue(); } } in.endObject(); // 返回具体的Event子类实例(需要根据你的业务调整) return new ConcreteEvent(title, text); } }
然后注册到Gson:
Gson gson = new GsonBuilder() .registerTypeAdapter(Event.class, new EventTypeAdapter()) .create();
内容的提问来源于stack exchange,提问作者Hyrial
相关产品推荐
相关产品推荐

