本文详解如何使用 jackson 正确反序列化含多层嵌套结构(如 `"resources": {"key": {"value": "test"}}`)的 json,指出常见类型误配错误(如将字符串值误映射为 `list
你遇到的 MismatchedInputException 根本原因在于 Java 类型声明与 JSON 实际结构严重不匹配:JSON 中 "value": "test" 是一个纯字符串,但你的字段却声明为 HashMap
观察原始 JSON:
{
"resources": {
"foo": { "value": "test" },
"bar": { "value": "test" }
}
}// ResourceEntry.java —— 表示每个资源条目
public class ResourceEntry {
private String value;
// 必须提供无参构造器(Jackson 反序列化所需)
public ResourceEntry() {}
public String getValue() { return value; }
public void setValue(String value) { this.value = value; }
@Override
public String toString() {
return "ResourceEntry{value='" + value + "'}";
}
}
// JsonTwoJavaFileModel.java —— 根对象
public class JsonTwoJavaFileModel {
@JsonProperty("resources")
private Map resources;
public Map getResources() {
return resources;
}
public void setResources(Map resources) {
this.resources = resources;
}
} 使用方式(简洁可靠):
ObjectMapper mapper = new ObjectMapper();
JsonTwoJavaFileModel model = mapper.readValue(
new File("data.json"),
JsonTwoJavaFileModel.class
);
System.out.println(model.getResources().get("foo").getValue()); // 输出: test你尝试的:
private HashMap>> stringListHashMap;
存在三重问题:
? 补充说明:即使改用 TypeReference(如答案中所示),HashMap 虽能“绕过”编译错误,但仍是脆弱且不可读的硬编码结构,仅适用于临时脚本或原型验证,绝不推荐用于生产代码。
若 "foo" 下未来可能包含更多字段(如 "type": "string", "required": true),可进一步增强 ResourceEntry:
public class ResourceEntry {
private String value;
private String type;
private Boolean required;
// getters & setters + no-arg constructor
}Jackson 会自动忽略 JSON 中不存在的字段(默认行为),新增字段无需修改反序列化逻辑。
| 问题点 | 正确做法 |
|---|---|
| List |
→ 改为 String value 字段 |
| 过度依赖 HashMap 嵌套泛型 | → 使用语义化 POJO + Map |
| 缺少无参构造器或访问器 | → 确保所有实体类有 public 无参构造器及 getter/setter |
| 忽略 Jackson 默认配置 | → ObjectMapper 默认启用 DEFAULT_TYPING 关闭,无需额外配置 |
遵循「JSON 结构即对象契约」原则,用清晰、可读、可演化的 Java 类型建模,才是 Jackson 高效稳定使用的基石。