Jackson如何兼容JSON对象/字符串格式反序列化成员对象
实现方案
Jackson完全支持该需求,无需修改全局ObjectMapper配置,仅通过字段注解+自定义反序列化器即可同时兼容两种JSON格式,实现步骤如下:
1. 编写自定义反序列化器
核心逻辑是在反序列化details字段时,先判断当前JSON节点的类型:如果是嵌套JSON对象,走默认解析逻辑;如果是字符串类型,先取出字符串内容,再将字符串内容作为JSON二次解析为UserDetails对象。
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; public class FlexibleUserDetailsDeserializer extends JsonDeserializer<UserDetails> { // 内部复用ObjectMapper解析字符串内嵌的JSON,可按需单独配置序列化规则 private static final ObjectMapper INNER_MAPPER = new ObjectMapper(); @Override public UserDetails deserialize(JsonParser parser, DeserializationContext context) throws IOException { // 匹配details为字符串的场景 if (parser.currentToken() == JsonToken.VALUE_STRING) { String detailsJsonStr = parser.getValueAsString(); return INNER_MAPPER.readValue(detailsJsonStr, UserDetails.class); } // 匹配details为正常JSON对象的场景,走默认解析逻辑 return parser.readValueAs(UserDetails.class); } }
2. 给目标字段添加注解指定反序列化器
在User类的details字段上添加@JsonDeserialize注解,绑定上面实现的自定义反序列化器即可。注意需要保证Jackson能访问到实体类的字段/属性,要么写全getter/setter,要么配置Jackson允许直接访问私有字段。
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; public class User { Integer id; @JsonDeserialize(using = FlexibleUserDetailsDeserializer.class) UserDetails details; // getter/setter 示例,也可通过Lombok的@Data注解自动生成 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public UserDetails getDetails() { return details; } public void setDetails(UserDetails details) { this.details = details; } }
对应的UserDetails类同理补全getter/setter即可:
public class UserDetails { String name; Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
效果验证
直接运行测试代码即可正常解析两种格式的JSON,不会抛出类型不匹配异常,两种场景下User对象的id、details.name、details.age属性都能正确赋值:
ObjectMapper mapper = new ObjectMapper(); // 解析嵌套对象格式的JSON User user1 = mapper.readValue(jsonString1, User.class); // 解析details为JSON字符串格式的JSON User user2 = mapper.readValue(jsonString2, User.class);
补充说明:该方案为字段级配置,仅对
User类的details字段生效,不会影响ObjectMapper对其他业务对象的反序列化逻辑,侵入性极低。
内容的提问来源于stack exchange,提问作者samarendra chandan bindu Dash
相关产品推荐
相关产品推荐

