How do I configure Jackson Serialization on LocalDateTime and LocalDate for Java?

非 Y 不嫁゛ 提交于 2021-02-04 08:14:25

问题


I know that there are many posts on Stackoverflow regarding this topic and I'm sure I've read just about all of them, but I am still struggling to get this working and would appreciate any guidance.

This is the Spring Parent and Jackson Dependencies I am using:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.9.RELEASE</version>
</parent>

<!-- Jackson -->
<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

Within my Application Configuration I am trying to use:

@Autowired
void configureJackson(ObjectMapper jackson2ObjectMapper) {

    JavaTimeModule timeModule = new JavaTimeModule();

    timeModule.addDeserializer(LocalDate.class,
            new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

    timeModule.addDeserializer(LocalDateTime.class,
            new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

    timeModule.addSerializer(LocalDate.class,
            new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

    timeModule.addSerializer(LocalDateTime.class,
            new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

    jackson2ObjectMapper
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
            .setSerializationInclusion(JsonInclude.Include.NON_NULL)
            .registerModule(timeModule)
            .registerModule(new ParameterNamesModule())
            .registerModule(new Jdk8Module())
            .registerModule(new JtsModule());
}

This is the model I am testing with. (I am trying to achive the same in 5-6 models).

public class DateRange implements Serializable {

     private static final long serialVersionUID = 6412487507434252330L;

     private LocalDateTime startTime;
     private LocalDateTime endTime;

     private LocalDate startDate;
     private LocalDate endDate;

     // Getters/Setters

I am hoping that I could find an approach that would apply globally without the need for me to annotate each field individually. I was using java.util.Date before, but ran into some issues with other functionality there.

Trying to use these newer (better) date models instead of that old damaged one is causing me a lot of headache over a simple thing.


Update

I changed my configuration to one of the suggested below and came really close to solving this issue.

@Bean
@Primary
public ObjectMapper objectMapper() {

    JavaTimeModule timeModule = new JavaTimeModule();

    timeModule.addDeserializer(LocalDate.class,
            new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

    timeModule.addDeserializer(LocalDateTime.class,
            new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

    timeModule.addSerializer(LocalDate.class,
            new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

    timeModule.addSerializer(LocalDateTime.class,
            new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

    return new ObjectMapper()
            //.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
            .setSerializationInclusion(JsonInclude.Include.NON_NULL)
            .registerModule(timeModule)
            .registerModule(new ParameterNamesModule())
            .registerModule(new Jdk8Module())
            .registerModule(new JtsModule());
}

Now the only issue I have is that LocalDateTime is printing timestamps like: "2018-07-26T07:57:12.938" when I need them like: 2018-07-26 07:57:12.

These fields are already in-use today and I need to make this change seamless in a way that doesn't require my API consumers to make any adjustments.

Cassio mentioned that disabling SerializationFeature.WRITE_DATES_AS_TIMESTAMPS will print timestamps in this ISO format, but it's not what I need. I tried to comment out the field in the hopes that it would pickup the custom DateTimeFormatter I am providing, however it has not changed my output.


回答1:


The JavaTimeModule will do the hard work for you. It provides a set of serializers and deserializers for for the java.time types. If the SerializationFeature.WRITE_DATES_AS_TIMESTAMPS is disabled, java.time types will be serialized in standard ISO-8601 string representations.


By default, Spring will provide you with an instance of ObjectMappper created by the Jackson2ObjectMapperBuilder. This instance is auto-configured for you. See the class documentation for details.

If you want to replace the default ObjectMapper completely, either define a @Bean of that type and mark it as @Primary:

@Bean
@Primary
public ObjectMapper objectMapper() {    
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new JavaTimeModule());
    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    return mapper;
}

Or, if you prefer the builder-based approach, define a Jackson2ObjectMapperBuilder @Bean.

@Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.modules(new JavaTimeModule());
    builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    return builder;
}

Note that, in either case, doing so disables all auto-configuration of the ObjectMapper. See the documentation for details.




回答2:


I finally got this working with the help of Cassio and some other digging on the web. Looking back I think the issue was that I was defining the custom formats on the JavaTimeModule, but I needed to define them on the mapper instead.

@Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
    return new Jackson2ObjectMapperBuilder()
            .createXmlMapper(false)
            .indentOutput(true)
            .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
            .serializers(
                    new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")),
                    new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
            .deserializers(
                    new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")),
                    new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
            .modules(
                    new JavaTimeModule(),
                    new ParameterNamesModule(),
                    new Jdk8Module(),
                    new JtsModule());
}

https://github.com/spring-projects/spring-boot/issues/4217

http://www.baeldung.com/jackson-serialize-dates




回答3:


You can also solve this to expose this instance:

@Bean
public Jackson2ObjectMapperBuilder configureObjectMapper() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.modules(new JavaTimeModule(),new ParameterNamesModule(),new Jdk8Module());
    builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    return builder;
}


来源:https://stackoverflow.com/questions/51527794/how-do-i-configure-jackson-serialization-on-localdatetime-and-localdate-for-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!