如何在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
相关产品推荐
相关产品推荐

