Spring Boot 不为 ZonedDateTime 使用自定义反序列化器

Posted

技术标签:

【中文标题】Spring Boot 不为 ZonedDateTime 使用自定义反序列化器【英文标题】:Spring Boot doesn't use custom deserializer for ZonedDateTime 【发布时间】:2019-01-01 00:04:47 【问题描述】:

我正在尝试设置我的 Spring Boot 配置以使用我的自定义 serializerdeserializer。

反序列化代码

public class CustomZonedDateTimeDeserializer extends JsonDeserializer<ZonedDateTime> 

    @Override
    public ZonedDateTime deserialize(JsonParser jsonParser, DeserializationContext context)
            throws IOException, JsonProcessingException 
        ObjectCodec oc = jsonParser.getCodec();
        TextNode node = (TextNode) oc.readTree(jsonParser);
        String dateString = node.textValue();
        return ZonedDateTime.parse(dateString, CustomZonedDateTimeSerializer.formatter);
    

@Override
public Class<?> handledType() 
    return ZonedDateTime.class;

序列化代码

public class CustomZonedDateTimeSerializer extends JsonSerializer<ZonedDateTime> 

    @Override
    public Class<ZonedDateTime> handledType() 
        return ZonedDateTime.class;
    

    public final static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");

    @Override
    public void serialize(ZonedDateTime date, JsonGenerator generator, SerializerProvider provider)
            throws IOException, JsonProcessingException 
        final String dateString = date.format(formatter);
        generator.writeString(dateString);

    


这是我的配置:

@Configuration
public class JacksonConfiguration 

    @Autowired
    Jackson2ObjectMapperBuilder jacksonBuilder;

    @PostConstruct
    public void configureJackson() 

        final CustomZonedDateTimeSerializer serializer = new CustomZonedDateTimeSerializer();
        jacksonBuilder.serializers(serializer);

        final CustomZonedDateTimeDeserializer deserializer = new CustomZonedDateTimeDeserializer();
        jacksonBuilder.deserializers(deserializer);
    


我正在创建一个 REST API,所以我的控制器中有这个:

@RequestMapping(value = "date", method =  RequestMethod.GET )
@ApiOperation(value = "", notes = "")
public ResponseWrapper<String> testDATE(
        @RequestParam @ApiParam(value = "", required = true) ZonedDateTime date) 
    System.out.println(date.toString());
    return new ResponseWrapper<String>(date.toString());

到目前为止我已经尝试过: 创建一个自定义模块并将其作为@Bean 添加到配置中,将序列化器和反序列化器添加到配置中的jackonBuilder 对象以及类似于此example 中的代码

我是否遗漏了什么或做错了什么? 每次我尝试都会收到以下错误:

“将'java.lang.String'类型的值转换为所需类型失败 'java.time.ZonedDateTime';嵌套异常是 org.springframework.core.convert.ConversionFailedException: 失败 从类型 [java.lang.String] 转换为类型 [@org.springframework.web.bind.annotation.RequestParam @io.swagger.annotations.ApiParam java.time.ZonedDateTime] 的价值 '2018-07-10T00:00:00+0000';嵌套异常是 java.lang.IllegalArgumentException:值的解析尝试失败 [2018-07-10T00:00:00+0000]"

我每次都发送以下值:2018-07-10T00:00:00+0000 并且该值甚至没有到达我有断点的解串器。

【问题讨论】:

您必须为Jackson2ObjectMapperBuilder 提供工厂方法。我认为这里发生的事情是,当你的 @PostConstruct 被执行时, ObjectMapper 已经被创建了——但这只是一个假设。 您是否尝试过改用org.springframework.core.convert.converter.Converter?我发现反序列化要简单得多。 Spring-boot 应该自动注册你的序列化器和反序列化器类。确保它们位于自动扫描包层次结构中。删除您的 JacksonConfiguration 类 - 将为您配置 spring 提供的可注入 ObjectMapper。 【参考方案1】:

在你的配置类中添加这个 bean:

@Bean
public Jackson2ObjectMapperBuilder configureObjectMapper() 
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    final CustomZonedDateTimeSerializer serializer = new CustomZonedDateTimeSerializer();
    builder.serializers(serializer);

    final CustomZonedDateTimeDeserializer deserializer = new CustomZonedDateTimeDeserializer();
    builder.deserializers(deserializer);
    return builder;

【讨论】:

这可行(我之前试过),但我的问题是我使用了错误的 http 方法【参考方案2】:

似乎我无法在 GET 请求中发送 ZonedDateTime。一旦我更改为 POST,Spring 就能够自动解析日期。

我只添加了 spring.jackson.deserialization.adjust_dates_to_context_time_zone=true,所以它考虑了时区。

如果有人想在 GET 中发送它,他必须发送一个字符串并解析它,而不是将 ZonedDateTime 定义为参数。

【讨论】:

以上是关于Spring Boot 不为 ZonedDateTime 使用自定义反序列化器的主要内容,如果未能解决你的问题,请参考以下文章

如何为某些 Spring Boot Micrometer 指标提供标签,但不为其他指标提供标签?

Spring boot rest api - 我可以在不为响应对象创建任何 java 类(DTO 或实体)的情况下获得响应吗?

推荐 9 个 Spring Boot 开源项目

(转)Spring Boot Junit单元测试

Spring Boot 和 Thymeleaf 在字段错误时返回 400 错误

spring-boot 构建上传到nexus私服