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

如何在Gson反序列化JSON时添加枚举值有效性校验?

解决Gson反序列化枚举时的无效值校验问题

我来给你捋捋这个问题的解决方案——Gson默认处理枚举的时候,碰到无效值只会默默返回null,不会主动抛出异常,这确实挺坑的,但我们可以通过自定义TypeAdapter来补上这个校验逻辑,确保反序列化时一旦遇到非法枚举值就立刻报错。

方法一:为特定枚举编写自定义TypeAdapter

针对你的AccessMode枚举,我们可以专门写一个类型适配器,在读取JSON值时主动校验是否为有效枚举值:

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import com.google.gson.JsonSyntaxException;
import java.io.IOException;

public class AccessModeTypeAdapter extends TypeAdapter<AccessMode> {
    @Override
    public void write(JsonWriter out, AccessMode value) throws IOException {
        // 序列化时直接写出枚举的名称
        out.value(value.name());
    }

    @Override
    public AccessMode read(JsonReader in) throws IOException {
        String modeStr = in.nextString();
        try {
            // 尝试解析为枚举值
            return AccessMode.valueOf(modeStr);
        } catch (IllegalArgumentException e) {
            // 解析失败时抛出Gson的JsonSyntaxException,方便上层捕获处理
            throw new JsonSyntaxException("无效的AccessMode枚举值: " + modeStr, e);
        }
    }
}

接下来需要把这个适配器注册到Gson实例中:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

Gson gson = new GsonBuilder()
        .registerTypeAdapter(AccessMode.class, new AccessModeTypeAdapter())
        .create();

这样当你反序列化包含无效值的JSON(比如{"access": "READ_XXX"})时,fromJson()方法就会抛出JsonSyntaxException,你可以在业务代码中捕获这个异常并做相应处理(比如返回错误提示、记录日志等)。

方法二:通用枚举TypeAdapter(复用性更强)

如果你的项目中有多个枚举需要做无效值校验,写多个适配器太麻烦,我们可以写一个泛型的通用适配器:

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import com.google.gson.JsonSyntaxException;
import java.io.IOException;

public class ValidatingEnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> {
    private final Class<T> enumClass;

    public ValidatingEnumTypeAdapter(Class<T> enumClass) {
        this.enumClass = enumClass;
    }

    @Override
    public void write(JsonWriter out, T value) throws IOException {
        if (value == null) {
            out.nullValue();
        } else {
            out.value(value.name());
        }
    }

    @Override
    public T read(JsonReader in) throws IOException {
        String valueStr = in.nextString();
        try {
            return Enum.valueOf(enumClass, valueStr);
        } catch (IllegalArgumentException e) {
            throw new JsonSyntaxException(
                String.format("无效的%s枚举值: %s", enumClass.getSimpleName(), valueStr),
                e
            );
        }
    }
}

注册时只需要传入对应的枚举类即可:

Gson gson = new GsonBuilder()
        .registerTypeAdapter(AccessMode.class, new ValidatingEnumTypeAdapter<>(AccessMode.class))
        // 其他枚举也可以用同一个适配器
        // .registerTypeAdapter(AnotherEnum.class, new ValidatingEnumTypeAdapter<>(AnotherEnum.class))
        .create();

测试示例

你可以用下面的代码验证效果:

// 测试有效JSON
String validJson = "{\"access\": \"READ_WRITE\"}";
YourDataClass validData = gson.fromJson(validJson, YourDataClass.class);
System.out.println("有效值反序列化结果: " + validData.getAccess());

// 测试无效JSON
String invalidJson = "{\"access\": \"READ_XXX\"}";
try {
    YourDataClass invalidData = gson.fromJson(invalidJson, YourDataClass.class);
} catch (JsonSyntaxException e) {
    System.err.println("捕获到无效枚举值错误: " + e.getMessage());
}

这样就能完美解决Gson默认不校验枚举无效值的问题啦!

内容的提问来源于stack exchange,提问作者geschema

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:12:27