fastjson2反序列化白名单必须显式配置,否则抛jsonreaderexception;启用autotype需同时开启supportautotype并传入autotypeaccept白名单,不支持通配符,包路径末尾加.表示该包下所有类。

Fastjson2 的反序列化白名单必须显式配置
Fastjson2 默认关闭 autoType(即不自动识别类名),不配白名单会直接抛 JSONReaderException: autoType is not support。这不是警告,是硬性拦截——哪怕你传的是 {"@type":"java.util.ArrayList"} 也会被拒。
白名单不是可选项,是启用 autoType 的前提。而 autoType 又是反序列化带类信息 JSON(比如 Fastjson2 序列化时用了 SerializerFeature.WriteClassName)的必要条件。
常见错误现象:redisTemplate.opsForValue().get("user:1") 返回 null,日志里却只看到一行模糊的 parse error,实际就是白名单缺失导致静默失败。
- 白名单需在
JSONReader.Feature级别启用,不能靠全局配置或 VM 参数绕过 - 只允许添加具体类或包路径,不支持通配符(如
com.example.**不合法) - 包路径末尾加
.表示该包下所有类,例如"com.example.model."
RedisTemplate 中嵌入白名单的正确写法
不能只在 JSON.parseObject(bytes, clazz) 里传类型,还要把白名单塞进 JSONReader.Context。否则即使类存在,@type 字段仍被忽略。
示例中常见的错误是直接用 JSON.parseObject(bytes, Object.class) ——这会丢失类型信息,且不触发白名单校验逻辑。
正确做法是使用带 JSONReader.Feature 的重载,并显式传入白名单:
@Override
public Object deserialize(byte[] bytes) {
if (bytes == null || bytes.length == 0) return null;
String str = new String(bytes, StandardCharsets.UTF_8);
return JSON.parseObject(str, Object.class,
JSONReader.Feature.SupportAutoType,
JSONReader.Feature.FieldBased,
JSONReader.Feature.IgnoreExtraField,
JSONReader.Feature.UseDefaultConstructor,
// 白名单必须在这里声明
JSONReader.Feature.AutoTypeAccept("com.example.model.", "java.util.")
);
}
- 多个白名单用逗号分隔,但每个都得是独立的
JSONReader.Feature.AutoTypeAccept(...) -
SupportAutoType必须开启,否则白名单无效 -
IgnoreExtraField建议带上,避免新增字段引发反序列化失败(对应你知识库中提到的 FAIL_ON_UNKNOWN_PROPERTIES 场景)
Redisson 自定义 Codec 的白名单处理更隐蔽
Redisson 的 Codec 接口不暴露 JSON 配置入口,encode/decode 方法里若用 Fastjson2,白名单必须在每次 JSON.parseObject 调用时重复指定——没有“全局注册”机制。
容易踩的坑是:在 CustomCodec.decode() 里写了白名单,但忘了在 encode() 里加 WriteClassName,导致存进去的 JSON 没带 @type,读出来自然还是 LinkedHashMap。
-
encode中必须用JSON.toJSONString(obj, SerializerFeature.WriteClassName) -
decode中必须匹配使用JSON.parseObject(str, clazz, features...)并带白名单 - 如果业务中混合使用泛型(如
List<user></user>),白名单还得包含java.util.ArrayList和目标元素类
白名单漏配的典型表现和定位方法
最麻烦的不是报错,而是“看起来成功但结果不对”:比如存的是 User,取出来却是 LinkedHashMap,字段值还在,但类型丢了,后续调用 user.getName() 就 NPE。
这种问题不会抛异常,日志也安静,只能靠断点进 deserialize 方法,看 JSON.parseObject 返回值类型是否符合预期。
- 检查 Redis 里原始 value:用
redis-cli get key看是否含@type字段;不含说明serialize没开WriteClassName - 检查反序列化后类型:不要只打印
toString(),用obj.getClass().getName()确认 - 白名单路径大小写敏感,
com.example.Model和com.example.model是两个世界











