启用默认类型时Jackson databind v2.9.4反序列化java.lang.Long泛型失败
我帮你分析下问题根源,再给出几个可行的解决方案:
问题原因
你配置的enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY)只会给非final类自动添加类型标识属性,而java.lang.Long是final类,所以Jackson不会为它生成类型信息。当反序列化泛型类型(比如List<Long>)时,Java的类型擦除会导致Jackson无法仅凭容器类(比如List.class)推断出泛型参数的具体类型,没有类型信息辅助的话,Jackson很可能把JSON里的数值解析成Integer,进而无法转换为Long,最终导致反序列化失败。
另外,你配置的FAIL_ON_UNKNOWN_PROPERTIES=false可能会掩盖部分错误提示,让问题排查更困难。
解决方案
方案一:用TypeReference明确指定泛型类型(推荐)
这是Jackson处理泛型反序列化的标准方式,不需要修改现有ObjectMapper配置,只需要在反序列化时传递TypeReference对象来保留泛型信息:
// 示例:反序列化List<Long> String jsonData = "[100, 200, 300]"; List<Long> longList = objectMapper.readValue(jsonData, new TypeReference<List<Long>>() {});
这种方法避免了类型擦除带来的问题,同时不会引入额外的安全风险。
方案二:调整默认类型检测范围(注意安全风险)
如果你的场景需要Jackson自动处理泛型类型,可以把DefaultTyping的范围改成更宽泛的选项,比如OBJECT_AND_NON_CONCRETE:
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE, JsonTypeInfo.As.PROPERTY);
⚠️ 重要提醒:enableDefaultTyping在Jackson 2.9版本中已经被标记为过时,而且存在反序列化安全漏洞(恶意JSON可能触发任意代码执行)。如果你的项目允许升级Jackson版本,建议改用安全的替代方法:
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
方案三:自定义泛型反序列化器(特定场景用)
如果前两种方案不适合你的业务场景,可以为目标泛型类型自定义反序列化器,注册到ObjectMapper中:
SimpleModule longGenericModule = new SimpleModule(); // 为List<Long>注册自定义反序列化器 longGenericModule.addDeserializer( new TypeReference<List<Long>>(){}.getType(), new JsonDeserializer<List<Long>>() { @Override public List<Long> deserialize(JsonParser parser, DeserializationContext context) throws IOException { List<Long> resultList = new ArrayList<>(); while (parser.nextToken() != JsonToken.END_ARRAY) { // 强制读取为Long类型 resultList.add(parser.getLongValue()); } return resultList; } } ); objectMapper.registerModule(longGenericModule);
这个方法比较繁琐,只建议在特殊业务场景下使用。
内容的提问来源于stack exchange,提问作者SRH LABS

