You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将嵌套结构JSON日期反序列化为Java LocalDateTime对象

解决Jackson反序列化嵌套结构LocalDateTime的问题

项目背景

Spring Boot + Gradle环境下,定义了如下Sale实体类:

public class Sale{
   private String storeNumber;
   @JsonFormat(pattern  = "yyyy-MM-dd'T'HH:mm:ss")
   private LocalDateTime saleDateTime;
   // getter、setter方法
}

需要将以下嵌套结构的JSON反序列化为Sale对象:

{
   "storeNumber": "023",
   "saleDateTime": {
     "date": {
      "year" : 2023,
      "month" : 4,
      "day" : 4
     },
     "time": {
      "hour" : 16,
      "minute" : 28,
      "second" : 45,
      "nano" : 0
     }
  }
}

使用ObjectMapper.readValue(json, Sale.class)时抛出异常:

MismatchedInputException: Cannot deserialize value of type 'java.time.LocalDateTime' from Object value (token 'JsonToken.START_OBJECT')

此前尝试添加jackson-datatype-jsr310依赖、注册JavaTimeModule、编写自定义反序列化器但未生效,以下是可行的解决方案:

解决方案步骤

1. 确认Gradle依赖

确保引入正确的Jackson JSR310模块依赖(版本与Spring Boot适配即可):

implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'

2. 编写自定义LocalDateTime反序列化器

针对嵌套的date和time节点,实现自定义反序列化逻辑:

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.LocalDateTime;
import java.time.Month;

public class NestedLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

    @Override
    public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        JsonNode rootNode = parser.getCodec().readTree(parser);
        JsonNode dateNode = rootNode.get("date");
        JsonNode timeNode = rootNode.get("time");

        // 解析日期部分
        int year = dateNode.get("year").asInt();
        Month month = Month.of(dateNode.get("month").asInt());
        int day = dateNode.get("day").asInt();

        // 解析时间部分
        int hour = timeNode.get("hour").asInt();
        int minute = timeNode.get("minute").asInt();
        int second = timeNode.get("second").asInt();
        int nano = timeNode.get("nano").asInt();

        return LocalDateTime.of(year, month, day, hour, minute, second, nano);
    }
}

3. 注册反序列化器

有两种注册方式,选其一即可:

方式一:字段级注解注册

直接在Sale类的saleDateTime字段上添加@JsonDeserialize注解:

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.time.LocalDateTime;

public class Sale {
    private String storeNumber;
    
    @JsonDeserialize(using = NestedLocalDateTimeDeserializer.class)
    private LocalDateTime saleDateTime;

    // getter、setter方法
}

方式二:全局ObjectMapper注册

如果需要全局生效,在配置类中自定义ObjectMapper并注册反序列化器:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JacksonConfig {
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        JavaTimeModule module = new JavaTimeModule();
        // 添加自定义反序列化器
        module.addDeserializer(LocalDateTime.class, new NestedLocalDateTimeDeserializer());
        mapper.registerModule(module);
        return mapper;
    }
}

4. 测试验证

编写测试代码验证反序列化效果:

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;

public class DeserializationTest {
    public static void main(String[] args) throws IOException {
        String json = "{\n" +
                "   \"storeNumber\": \"023\",\n" +
                "   \"saleDateTime\": {\n" +
                "     \"date\": {\n" +
                "      \"year\" : 2023,\n" +
                "      \"month\" : 4,\n" +
                "      \"day\" : 4\n" +
                "     },\n" +
                "     \"time\": {\n" +
                "      \"hour\" : 16,\n" +
                "      \"minute\" : 28,\n" +
                "      \"second\" : 45,\n" +
                "      \"nano\" : 0\n" +
                "     }\n" +
                "  }\n" +
                "}";

        ObjectMapper mapper = new ObjectMapper();
        // 如果是全局注册,直接注入ObjectMapper即可
        mapper.registerModule(new JavaTimeModule().addDeserializer(LocalDateTime.class, new NestedLocalDateTimeDeserializer()));
        
        Sale sale = mapper.readValue(json, Sale.class);
        System.out.println(sale.getSaleDateTime()); // 输出:2023-04-04T16:28:45
    }
}

问题原因说明

默认的JavaTimeModule仅支持ISO标准格式的日期字符串或单一字段的日期结构,无法解析这种拆分为date和time的嵌套对象,因此必须通过自定义反序列化器手动解析各节点字段并组装成LocalDateTime对象。

内容的提问来源于stack exchange,提问作者Bharadwaj Joshi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 16:39:58