
本文介绍在 jackson 中仅通过注解(不使用 typereference、自定义反序列化器或显式集合类型)将顶层为 json 数组(如 [{"name":"a"},{"name":"b"}])反序列化为含 list 字段的 java 封装类(如 getpersonsresponsedto)的可靠方案。核心在于合理使用 @jsoncreator 构造器注解。
Jackson 默认要求 JSON 结构与目标类结构严格匹配:若 JSON 以 [(START_ARRAY)开头,而目标类是普通 POJO(非集合类型),则会抛出 JsonMappingException: Can not deserialize instance of ... out of START_ARRAY token 异常。这是因为 Jackson 期望顶层 JSON 是一个对象 {},而非数组 []。
要解决此问题且仅使用注解(不依赖 TypeReference> 或 Person[].class),关键在于告诉 Jackson:该类可通过一个接收 List
以下是完整可行的实现:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
public class GetPersonsResponseDto {
public final List persons;
// ✅ 必须标注 @JsonCreator,且参数类型需与 JSON 数组元素类型一致(此处为 List)
@JsonCreator
public GetPersonsResponseDto(@JsonProperty("persons") List persons) {
this.persons = persons;
}
// 提供无参构造器(部分 Jackson 版本或配置下仍可能需要)
public GetPersonsResponseDto() {
this.persons = null;
}
}
public class Person {
public String name;
} ? 原理说明:当 Jackson 遇到顶层数组时,若目标类存在唯一带 @JsonCreator 的构造器,且其参数为 List(T 为可被自动解析的类型),它会尝试将整个 JSON 数组作为该参数值传入——无需额外配置,也无需 @JsonUnwrapped 或 @JsonValue 等干扰性注解。
✅ 使用方式保持简洁:
ObjectMapper mapper = new ObjectMapper(); GetPersonsResponseDto response = mapper.readValue(jsonInput, GetPersonsResponseDto.class); // response.persons 将正确包含两个 Person 实例
⚠️ 注意事项:
- 该方案在 Jackson 2.9+ 版本中稳定支持;若使用较老版本(如 2.6–2.8),建议升级或补充 @JsonFormat(shape = JsonFormat.Shape.ARRAY)(但对顶层数组无效,故不推荐);
- 构造器参数应使用 final 字段 + 显式 @JsonProperty(提高可读性与兼容性),避免仅靠参数名推断(受编译器 -parameters 影响);
- 不要同时保留字段赋值与 @JsonCreator 构造器逻辑冲突的 setter 方法,否则可能导致不可预期行为;
- 若后续需支持序列化(即 writeValue 输出相同数组格式),还需添加 @JsonUnwrapped 或使用 @JsonValue,但本例聚焦反序列化,故未展开。
总结:仅用 @JsonCreator 标注接收 List










