如何实现Jackson自定义反序列化器将多属性转为Validity值对象?
解决Validity自定义反序列化器的实现方案
这个场景我之前处理过,核心就是要让Jackson知道如何从扁平的JSON结构里提取字段,来构建嵌套的Validity值对象。下面是具体的实现步骤和代码示例:
1. 编写Validity的自定义反序列化器
我们需要继承Jackson的StdDeserializer,重写deserialize方法,从父级JSON节点中直接提取validFrom和validTo字段,转换为LocalDate后构建Validity对象:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import java.io.IOException; import java.time.LocalDate; public class ValidityDeserializer extends StdDeserializer<Validity> { // 必须的无参构造函数,供Jackson反射调用 public ValidityDeserializer() { this(null); } protected ValidityDeserializer(Class<?> vc) { super(vc); } @Override public Validity deserialize(JsonParser parser, DeserializationContext context) throws IOException { JsonNode parentNode = parser.getCodec().readTree(parser); // 从扁平JSON中提取日期字段 String validFromStr = parentNode.get("validFrom").asText(); String validToStr = parentNode.get("validTo").asText(); // 转换为LocalDate(如果JSON日期格式非标准,需指定DateTimeFormatter) LocalDate validFrom = LocalDate.parse(validFromStr); LocalDate validTo = LocalDate.parse(validToStr); return new Validity(validFrom, validTo); } }
2. 将反序列化器绑定到Validity类
有两种方式可以让Jackson识别这个自定义反序列化器:
方式一:直接在Validity类上添加注解
这种方式更直观,直接在类上标记使用我们的自定义反序列化器:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import java.time.LocalDate; @JsonDeserialize(using = ValidityDeserializer.class) public class Validity { private LocalDate validFrom; private LocalDate validTo; // 提供无参构造(Jackson默认需要)和全参构造 public Validity() {} public Validity(LocalDate validFrom, LocalDate validTo) { this.validFrom = validFrom; this.validTo = validTo; } // 省略getter和setter方法 }
方式二:在ObjectMapper中注册反序列化器
如果不想修改Validity类的注解,可以在初始化ObjectMapper时手动注册:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; public class DemoMain { public static void main(String[] args) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); // 注册JavaTimeModule,支持LocalDate的序列化/反序列化 objectMapper.registerModule(new JavaTimeModule()); // 绑定Validity类和自定义反序列化器 objectMapper.addDeserializer(Validity.class, new ValidityDeserializer()); // 测试反序列化 String json = "{ \"name\": \"name\", \"validFrom\": \"2018-01-09\", \"validTo\": \"2018-01-10\" }"; MyPojo myPojo = objectMapper.readValue(json, MyPojo.class); System.out.println("Name: " + myPojo.getName()); System.out.println("Valid From: " + myPojo.getValidity().getValidFrom()); System.out.println("Valid To: " + myPojo.getValidity().getValidTo()); } }
3. 确保MyPojo的注解配置正确
你的MyPojo类已经使用了@JsonUnwrapped,这个注解会告诉Jackson:反序列化时把父JSON中的validFrom和validTo字段传递给Validity的反序列化器,刚好和我们的自定义逻辑匹配:
import com.fasterxml.jackson.annotation.JsonUnwrapped; public class MyPojo { private String name; @JsonUnwrapped private Validity validity; // 无参构造和全参构造 public MyPojo() {} public MyPojo(String name, Validity validity) { this.name = name; this.validity = validity; } // 省略getter和setter方法 }
注意事项
- 处理
LocalDate需要依赖jackson-datatype-jsr310模块,记得在你的依赖管理工具(Maven/Gradle)中引入该依赖。 - 如果JSON中的日期格式不是标准的
yyyy-MM-dd,需要在LocalDate.parse时指定对应的DateTimeFormatter,或者在ObjectMapper中全局配置日期格式。
内容的提问来源于stack exchange,提问作者Patrik Mihalčin
相关产品推荐
相关产品推荐

