Deserialize Java 8 LocalDateTime with JacksonMapper

I read a few questions with answers here in SO regarding serialization and deserialization between java.time.LocalDateTime and the JSON property, but I can't get it to work.

I managed to configure the Spring boot application to return dates in the desired format ( YYY-MM-dd HH:mm ), but I have problems accepting the values ​​in this format in JSON.

This is all I have done so far:

Added maven dependency for jsr310 :

 <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> </dependency> 

Indicated by jsr310 in my main class:

 @EntityScan(basePackageClasses = { App.class, Jsr310JpaConverters.class }) 

Disable serialization as timestamps in application.properties :

 spring.jackson.serialization.write_dates_as_timestamps=false 

And this is my entity mapping for datetime:

 @Column(name = "start_date") @DateTimeFormat(iso = DateTimeFormat.ISO.TIME) @JsonFormat(pattern = "YYYY-MM-dd HH:mm") private LocalDateTime startDate; 

In my database, I store this date as TIMESTAMP in the following format: 2016-12-01T23:00:00+00:00 .

If I access this object through my controller, it returns JSON with the correct startDate format. When I try to publish it and deserialize it using the format YYYY-MM-dd HH:mm , I get the following exception:

 { "timestamp": "2016-10-30T14:22:25.285+0000", "status": 400, "error": "Bad Request", "exception": "org.springframework.http.converter.HttpMessageNotReadableException", "message": "Could not read document: Can not deserialize value of type java.time.LocalDateTime from String \"2017-01-01 20:00\": Text '2017-01-01 20:00' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {MonthOfYear=1, WeekBasedYear[WeekFields[SUNDAY,1]]=2017, DayOfMonth=1},ISO resolved to 20:00 of type java.time.format.Parsed\n at [Source: java.io.PushbackInputStream@679a734d ; line: 6, column: 16] (through reference chain: com.gigsterous.api.model.Event[\"startDate\"]); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not deserialize value of type java.time.LocalDateTime from String \"2017-01-01 20:00\": Text '2017-01-01 20:00' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {MonthOfYear=1, WeekBasedYear[WeekFields[SUNDAY,1]]=2017, DayOfMonth=1},ISO resolved to 20:00 of type java.time.format.Parsed\n at [Source: java.io.PushbackInputStream@679a734d ; line: 6, column: 16] (through reference chain: com.gigsterous.api.model.Event[\"startDate\"])", "path": "/api/events" } 

I know that there are many answers on this subject, but after them and attempts for several hours did not help me figure out what I was doing wrong, so I would be glad if someone could tell me what I’m missing, Thanks for any input on this!

EDIT: These are all the classes involved in the process:

Repository:

 @Repository public interface EventRepository extends PagingAndSortingRepository<Event, Long> { } 

Controller:

 @RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<Event> createEvent(@RequestBody Event event) { return new ResponseEntity<>(eventRepo.save(event), HttpStatus.CREATED); } 

My JSON requests payalod:

 { "name": "Test", "startDate": "2017-01-01 20:00" } 

Event:

 @Entity @Table(name = "events") @Getter @Setter public class Event { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "event_id") private long id; @Column(name = "name") private String name; @Column(name = "start_date") @DateTimeFormat(iso = DateTimeFormat.ISO.TIME) @JsonFormat(pattern = "YYYY-MM-dd HH:mm") private LocalDateTime startDate; } 
+23
source share
5 answers

The time you pass is not a local date format.

Change to

 @Column(name = "start_date") @DateTimeFormat(iso = DateTimeFormatter.ISO_LOCAL_DATE_TIME) @JsonFormat(pattern = "YYYY-MM-dd HH:mm") private LocalDateTime startDate; 

and enter the date string in the format '2011-12-03T10: 15: 30'.

But if you still want to transfer your own format, you just need to specify the correct formatter.

Change to

 @Column(name = "start_date") @DateTimeFormat(iso = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")) @JsonFormat(pattern = "YYYY-MM-dd HH:mm") private LocalDateTime startDate; 

I think your problem in @DateTimeFormat has no effect. Because Jackson is doing the deserialization, and he knows nothing about the spring annotation, and I don't see a spring scan of this annotation in the context of deserialization.

Alternatively, you can try installing the formatter when registering the java time module.

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

Here is a test case with a deseralizer that works fine. You can try to completely get rid of this DateTimeFormat annotation.

 @RunWith(JUnit4.class) public class JacksonLocalDateTimeTest { private ObjectMapper objectMapper; @Before public void init() { JavaTimeModule module = new JavaTimeModule(); LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer); objectMapper = Jackson2ObjectMapperBuilder.json() .modules(module) .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) .build(); } @Test public void test() throws IOException { final String json = "{ \"date\": \"2016-11-08 12:00\" }"; final JsonType instance = objectMapper.readValue(json, JsonType.class); assertEquals(LocalDateTime.parse("2016-11-08 12:00",DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm") ), instance.getDate()); } } class JsonType { private LocalDateTime date; public LocalDateTime getDate() { return date; } public void setDate(LocalDateTime date) { this.date = date; } } 
+25
source

You used the wrong mailbox for the year:

 @JsonFormat(pattern = "YYYY-MM-dd HH:mm") 

Must be:

 @JsonFormat(pattern = "YYYY-MM-dd HH:mm") 

With this change, everything works as expected.

+15
source

You can implement your JsonSerializer

Cm:

What is your bean property

 @JsonProperty("start_date") @JsonFormat("YYYY-MM-dd HH:mm") @JsonSerialize(using = DateSerializer.class) private Date startDate; 

So implement your own class

 public class DateSerializer extends JsonSerializer<Date> implements ContextualSerializer<Date> { private final String format; private DateSerializer(final String format) { this.format = format; } public DateSerializer() { this.format = null; } @Override public void serialize(final Date value, final JsonGenerator jgen, final SerializerProvider provider) throws IOException { jgen.writeString(new SimpleDateFormat(format).format(value)); } @Override public JsonSerializer<Date> createContextual(final SerializationConfig serializationConfig, final BeanProperty beanProperty) throws JsonMappingException { final AnnotatedElement annotated = beanProperty.getMember().getAnnotated(); return new DateSerializer(annotated.getAnnotation(JsonFormat.class).value()); } } 

Try this after the publication result for us.

+2
source

UPDATE:

Change to:

 @Column(name = "start_date") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm", iso = ISO.DATE_TIME) @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm") private LocalDateTime startDate; 

JSON request:

 { "startDate":"2019-04-02 11:45" } 
0
source

This worked for me:

 import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat.ISO; @Column(name="end_date", nullable = false) @DateTimeFormat(iso = ISO.DATE_TIME) @JsonFormat(pattern = "yyyy-MM-dd HH:mm") private LocalDateTime endDate; 
0
source

Source: https://habr.com/ru/post/1011855/


All Articles