You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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字段。

步骤:

  1. 修改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;

    // 原有方法逻辑不变
}
  1. 初始化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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:36:52