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

如何在Jackson反序列化时将数组自动转为以id为键的HashMap?

Jackson反序列化时自动将List转为HashMap的实现方法

问题场景

现有如下JSON数据:

{
    "default": "ignore-me",
    "catalog": [
        {
            "id": "object-1",
            "name": "Object 1"
        },
        {
            "id": "object-3",
            "name": "Object 3"
        },
        {
            "id": "object-2",
            "name": "Object 2"
        }
    ]
}

目前使用Jackson通过以下代码解析:

ObjectMapper mapper = new ObjectMapper();
Catalogs catalogs = mapper.readValue(new File("/catalogs.json"), Catalogs.class);

对应的Java模型类如下:

Catalogs.java

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;

public class Catalogs {

  @JsonProperty("default")
  private String defaultField;

  private List<Catalog> catalogList;

  // getters / setters
}

Catalog.java

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class Catalog {

  private String id;
  private String name;

  // getters / setters
}

需求是将List<Catalog> catalogList转换为HashMap<String, Catalog>,这样就能通过已知的id快速获取对应条目,实现类似Catalog catalog = catalogs.getCatalogMap().get("object-1");的调用方式,问Jackson能否在反序列化过程中自动完成该类型转换?

实现方案

Jackson完全支持在反序列化过程中自动完成这个转换,有两种简洁的实现方式:

方式一:利用@JsonCreator构造函数转换

直接修改Catalogs类,通过带@JsonCreator注解的构造函数接收List参数,内部直接转为HashMap:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Catalogs {

  @JsonProperty("default")
  private String defaultField;

  private Map<String, Catalog> catalogMap;

  // 用于Jackson反序列化的构造函数
  @JsonCreator
  public Catalogs(
      @JsonProperty("default") String defaultField,
      @JsonProperty("catalog") List<Catalog> catalogList) {
    this.defaultField = defaultField;
    this.catalogMap = new HashMap<>();
    // 遍历List,将id作为key存入Map
    for (Catalog catalog : catalogList) {
      this.catalogMap.put(catalog.getId(), catalog);
    }
  }

  // 保留无参构造函数,兼容Jackson的默认序列化/其他场景
  public Catalogs() {}

  // getters / setters
  public Map<String, Catalog> getCatalogMap() {
    return catalogMap;
  }

  public void setCatalogMap(Map<String, Catalog> catalogMap) {
    this.catalogMap = catalogMap;
  }

  // 其他getter/setter...
}

这种方式无需额外编写反序列化器,代码简洁直观,Jackson会自动把JSON中的catalog数组注入到构造函数的List参数中,完成转换。

方式二:自定义反序列化器

如果需要更灵活的控制(比如处理空值、自定义key生成规则等),可以编写自定义反序列化器:

  1. 首先修改Catalogs类的字段类型,并添加注解指定使用自定义反序列化器:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.util.Map;

public class Catalogs {

  @JsonProperty("default")
  private String defaultField;

  @JsonProperty("catalog")
  @JsonDeserialize(using = CatalogListToMapDeserializer.class)
  private Map<String, Catalog> catalogMap;

  // getters / setters
}
  1. 编写自定义反序列化器CatalogListToMapDeserializer.java:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class CatalogListToMapDeserializer extends JsonDeserializer<Map<String, Catalog>> {

  @Override
  public Map<String, Catalog> deserialize(JsonParser parser, DeserializationContext context) throws IOException {
    ObjectMapper mapper = (ObjectMapper) parser.getCodec();
    JsonNode node = mapper.readTree(parser);
    Map<String, Catalog> catalogMap = new HashMap<>();
    
    Iterator<JsonNode> elements = node.elements();
    while (elements.hasNext()) {
      Catalog catalog = mapper.treeToValue(elements.next(), Catalog.class);
      if (catalog != null && catalog.getId() != null) {
        catalogMap.put(catalog.getId(), catalog);
      }
    }
    
    return catalogMap;
  }
}

两种方式都能实现需求,之后就可以通过catalogs.getCatalogMap().get("object-1")直接获取对应Catalog对象了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 04:45:19