如何通过自定义反序列化器使用Jackson解析GSON生成的含LocalDate字段的JSON
解决Jackson反序列化自定义日期结构的问题
这个问题我碰到过好多次——Jackson默认没法直接识别这种嵌套了year/month/day的日期结构,所以咱们得写个自定义反序列化器来处理它。下面一步步来搞定:
1. 先定义你的实体类
首先得有个对应JSON结构的实体类,比如叫Article,这里我推荐用Java 8的LocalDate来存日期(比老的Date类好用太多):
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import java.math.BigDecimal; import java.time.LocalDate; public class Article { private int id; private int articleNumber; // 用注解指定咱们的自定义反序列化器 @JsonDeserialize(using = CustomDateDeserializer.class) private LocalDate processDate; private BigDecimal price; // 一定要加无参构造器,Jackson需要它来实例化对象 public Article() {} // 别忘了写getter和setter方法 public int getId() { return id; } public void setId(int id) { this.id = id; } public int getArticleNumber() { return articleNumber; } public void setArticleNumber(int articleNumber) { this.articleNumber = articleNumber; } public LocalDate getProcessDate() { return processDate; } public void setProcessDate(LocalDate processDate) { this.processDate = processDate; } public BigDecimal getPrice() { return price; } public void setPrice(BigDecimal price) { this.price = price; } }
2. 编写自定义反序列化器
接下来写核心的CustomDateDeserializer,继承Jackson的StdDeserializer,重写deserialize方法来解析嵌套的日期字段:
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; import java.time.LocalDate; public class CustomDateDeserializer extends JsonDeserializer<LocalDate> { @Override public LocalDate deserialize(JsonParser parser, DeserializationContext context) throws IOException { // 把当前节点转成JsonNode,方便提取里面的year/month/day JsonNode dateNode = parser.getCodec().readTree(parser); int year = dateNode.get("year").asInt(); int month = dateNode.get("month").asInt(); int day = dateNode.get("day").asInt(); // 用拿到的数值构建LocalDate对象 return LocalDate.of(year, month, day); } }
3. 测试反序列化效果
最后写个测试代码,验证一下能不能正常解析你的JSON字符串:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import java.io.IOException; public class TestDeserialization { public static void main(String[] args) throws IOException { String json = "{ \"id\": 10, \"articleNumber\": 5009, \"processDate\": { \"year\": 2021, \"month\": 1, \"day\": 1 }, \"price\": 1.22 }"; ObjectMapper objectMapper = new ObjectMapper(); // 注册JavaTimeModule,不然Jackson识别不了LocalDate类型 objectMapper.registerModule(new JavaTimeModule()); Article article = objectMapper.readValue(json, Article.class); // 打印结果看看是否正确 System.out.println("ID: " + article.getId()); System.out.println("Article Number: " + article.getArticleNumber()); System.out.println("Process Date: " + article.getProcessDate()); System.out.println("Price: " + article.getPrice()); } }
额外小提示
- 如果你坚持要用老的
java.util.Date,只需要把实体类里的LocalDate换成Date,然后在反序列化器里用new GregorianCalendar(year, month-1, day).getTime()(注意Calendar的月份是从0开始的,要减1)。 - 除了用
@JsonDeserialize注解单独指定,你也可以把反序列化器注册到ObjectMapper全局生效,这样所有同类型的日期字段都能自动解析:SimpleModule module = new SimpleModule(); module.addDeserializer(LocalDate.class, new CustomDateDeserializer()); objectMapper.registerModule(module);
这样就能完美解决你遇到的processDate字段反序列化失败的问题啦!
内容的提问来源于stack exchange,提问作者akr
相关产品推荐
相关产品推荐

