How do I configure Jackson Serialization on LocalDateTime and LocalDate for Java?
Solution 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.
Solution 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
wheelerswebservices
Technologist with a background in programming and a lot of knowledge in Cloud Computing with platforms like AWS, Azure, and GCP. I'm incredibly fascinated by cutting edge technologies like AI, Blockchain, ML, and Quantum Computing.
Updated on June 05, 2022Comments
-
wheelerswebservices almost 2 years
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.
-
wheelerswebservices almost 6 yearsThis DateRange object above for one, but anywhere in my code that uses these classes LocalDateTime and LocalDate I want to be handled globally; if possible.
-
-
wheelerswebservices almost 6 yearsThanks for your answer. This helped me get a lot closer than I was, however, I can't seem to change the format that LocalDateTime is printed in; even when providing a custom DateTimeFormatter implementation. I updated my question above to show the code I tried and the updated progress towards solving this issue.
-
cassiomolin almost 6 years@jDub9 I've just created a standalone application, configured
ObjectMapper
with the serializers show in your question, serialized your model as JSON as the dates were serialized in the correct format. Also, uncomment.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS).
-
wheelerswebservices almost 6 yearsOkay so I uncommented that line, ran a mvn clean install to ensure my classpath wasn't using any old settings, and I am still seeing timestamps serialized as: 2018-07-26T07:57:12.938.
-
Philippe Simo over 2 yearsWondering how to get the ObjectMapper from this bean ? Inject it in a class:
@Autowired Jackson2ObjectMapperBuilder objectMapperBuilder;
thenObjectMapper mapper = objectMapperBuilder.build();