在真实项目里,Java应用常常需要对接结构不一致的JSON数据,例如同一个字段有时是字符串,有时是对象,或者某些节点干脆不存在。如果强行用固定POJO去映射,就会抛出转换异常。我们需要更灵活的方式来完成解析。

为什么固定实体类会失效
当接口返回如下两种不同结构时,传统做法很难兼容:
{
"user": "tom"
}
{
"user": { "name": "tom", "age": 20 }
}
如果定义user为String类型,第二种就会解析失败。下面介绍三种常用处理思路。
使用 Jackson 的 JsonNode
JsonNode 可以把任意 JSON 当作树来读取,不要求预先知道结构。
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Demo {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
String json = "{"user":{"name":"tom"}}";
JsonNode root = mapper.readTree(json);
JsonNode userNode = root.get("user");
if (userNode.isTextual()) {
System.out.println("用户名:" + userNode.asText());
} else if (userNode.isObject()) {
System.out.println("姓名:" + userNode.get("name").asText());
}
}
}
先转 Map 再按需取值
把数据读成 Map<String, Object>,再根据实际类型判断,适合字段变动频繁的场景。
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;
public class MapDemo {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
String json = "{"user":"tom"}";
Map<String, Object> map = mapper.readValue(json, new TypeReference<Map<String, Object>>() {});
Object user = map.get("user");
if (user instanceof String) {
System.out.println("字符串用户:" + user);
} else if (user instanceof Map) {
System.out.println("对象用户:" + ((Map) user).get("name"));
}
}
}
自定义反序列化器
当某种不一致结构反复出现,可以写自定义反序列化器统一处理。
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 java.io.IOException;
public class UserDeserializer extends JsonDeserializer<User> {
@Override
public User deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
JsonNode node = p.readValueAsTree();
User user = new User();
if (node.isTextual()) {
user.setName(node.asText());
} else if (node.isObject()) {
user.setName(node.get("name").asText());
}
return user;
}
}
方案对比
| 方式 | 适用场景 | 维护成本 |
|---|---|---|
| JsonNode | 临时读取、结构极不稳定 | 低 |
| Map 接收 | 字段动态较多 | 中 |
| 自定义反序列化 | 固定多变模式 | 高但复用好 |
小结
面对结构不一致的 JSON,不要盲目加实体类。根据数据混乱程度选择 JsonNode、Map 或自定义反序列化,可显著提升 Java 解析代码的健壮性。