Jackson反序列化含大量动态节点的JSON时结果为空如何解决
方案1:无需自定义反序列化器(更简洁)
你的JSON结构本身就是标准键值对结构,Jackson原生支持直接反序列化为Map<String, Language>,完全不需要自己开发自定义反序列化逻辑:
- 首先定义基础
Language实体类:
public class Language { // 存储动态的语言名称(比如English、Spanish) private String name; // 对应JSON里的hex字段 private String hex; // 补全getter、setter、无参构造方法即可 }
- 直接执行反序列化再转List即可:
ObjectMapper objectMapper = new ObjectMapper(); // 第一步直接把JSON反序列为Map Map<String, Language> langMap = objectMapper.readValue( new ClassPathResource("data/languages.json").getFile(), new TypeReference<Map<String, Language>>() {} ); // 第二步把Map的键作为语言名赋值,直接转为目标List List<Language> languages = langMap.entrySet().stream() .map(entry -> { Language lang = entry.getValue(); lang.setName(entry.getKey()); return lang; }) .toList();
该方案代码量少、出错概率低,几千条数据的处理性能完全达标。
方案2:修复现有自定义反序列化器
你当前代码返回空列表的核心原因有两个:
@JsonDeserialize标注位置错误:你把注解加在了LanguageWrapper的languages字段上,但你的JSON根节点并没有languages字段,反序列化器拿到的节点为空,自然没有数据- 反序列化逻辑没有给
Language对象赋值字段,空构建的对象当然没有有效数据
修复步骤:
- 完善反序列化器逻辑:
static class LanguageDeserializer extends StdDeserializer<ArrayList<Language>> { // 必须补全无参构造,指定反序列化目标类型 public LanguageDeserializer() { super(ArrayList.class); } @Override public ArrayList<Language> deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException { final JsonNode node = jp.getCodec().readTree(jp); final Iterator<Map.Entry<String, JsonNode>> nodes = node.fields(); final ArrayList<Language> results = new ArrayList<>(); while (nodes.hasNext()) { Map.Entry<String, JsonNode> entry = nodes.next(); // 取动态键作为语言名,取子节点的hex属性赋值 Language lang = new Language(); lang.setName(entry.getKey()); lang.setHex(entry.getValue().get("hex").asText()); results.add(lang); } return results; } }
- 调整
LanguageWrapper的注解位置:
// 注解加在类上,因为整个JSON根节点就是要反序列化的内容 @JsonDeserialize(using = Language.LanguageDeserializer.class) public class LanguageWrapper extends ArrayList<Language> { // 直接继承ArrayList即可,不需要额外定义languages字段 }
- 原有反序列化调用代码无需修改,执行后就能拿到正常填充的列表。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

