no String-argument constructor/factory method to deserialize from String value ('2018-12-14')
Solution 1
I think the problem is here
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
return new ObjectMapper();
}
You must return configured objectMapper
instead of new instance:
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
objectMapper.registerModule(new JavaTimeModule()
.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("M/d/yyyy")))
.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("M/d/yyyy"))))
return objectMapper;
}
Solution 2
I faced the same issue recently and reason for the error was there are double quotes around my json string which when I removed it worked perfectly fine
Related videos on Youtube
Nenad Bulatović
Software Developer and Business Analyst/Consultant Java, C/C++, C#, Linux enthusiast Blog: http://nenadbulatovic.blogspot.com/
Updated on June 04, 2022Comments
-
Nenad Bulatović almost 2 years
This question is almost same as this one, but it differs in that I am trying to get String to LocalDate. Here is error from STS:
2018-12-14 00:47:04.507 WARN 6216 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Can not construct instance of java.time.LocalDate: no String-argument constructor/factory method to deserialize from String value ('2018-12-14'); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.time.LocalDate: no String-argument constructor/factory method to deserialize from String value ('2018-12-14') at [Source: java.io.PushbackInputStream@73ff9989; line: 3, column: 16] (through reference chain: com.xxxxx.xxxxxx.model.request.ReservationRequest["checkin"])]
and here is from Postman:
{ "timestamp": 1544744824516, "status": 400, "error": "Bad Request", "exception": "org.springframework.http.converter.HttpMessageNotReadableException", "message": "JSON parse error: Can not construct instance of java.time.LocalDate: no String-argument constructor/factory method to deserialize from String value ('2018-12-14'); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.time.LocalDate: no String-argument constructor/factory method to deserialize from String value ('2018-12-14')\n at [Source: java.io.PushbackInputStream@73ff9989; line: 3, column: 16] (through reference chain: com.xxxxx.xxxxx.model.request.ReservationRequest[\"checkin\"])", "path": "/room/reservation/v1" }
And POST request was:
{ "id": 12345, "checkin": "2018-12-14", "checkout": "2018-12-17" }
Where relevant classes are:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; @Configuration public class ApiConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new JavaTimeModule()); return new ObjectMapper(); } @Bean public ObjectWriter objectWriter(ObjectMapper objectMapper) { return objectMapper.writerWithDefaultPrettyPrinter(); } }
and
import java.time.LocalDate; import org.springframework.format.annotation.DateTimeFormat; public class ReservationRequest { private Long id; @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) private LocalDate checkin; @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) private LocalDate checkout; public ReservationRequest() { super(); } public ReservationRequest(Long id, LocalDate checkin, LocalDate checkout) { super(); this.id = id; this.checkin = checkin; this.checkout = checkout; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public LocalDate getCheckin() { return checkin; } public void setCheckin(LocalDate checkin) { this.checkin = checkin; } public LocalDate getCheckout() { return checkout; } public void setCheckout(LocalDate checkout) { this.checkout = checkout; } }
and
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.xxxxx.xxxxxx.model.request.ReservationRequest; import com.xxxxx.xxxxxx.model.response.ReservationResponse; @RestController @RequestMapping(ResourceConstants.ROOM_RESERVATION_V1) public class ReservationResource { @RequestMapping(path = "", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<ReservationResponse> getAvaiableRooms( @RequestParam(value = "checkin") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate checkin, @RequestParam(value = "checkout") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate checkout) { return new ResponseEntity<>(new ReservationResponse(), HttpStatus.OK); } @RequestMapping(path = "", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<ReservationResponse> createReservation(@RequestBody ReservationRequest reservationRequest) { return new ResponseEntity<>(new ReservationResponse(), HttpStatus.CREATED); } @RequestMapping(path = "", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_UTF8_VALUE, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<ReservationResponse> updateReservation(@RequestBody ReservationRequest reservationRequest) { return new ResponseEntity<>(new ReservationResponse(), HttpStatus.OK); } @RequestMapping(path = "/{reservationId}", method = RequestMethod.DELETE) public ResponseEntity<Void> deleteReservation(@PathVariable long reservationId) { return new ResponseEntity<>(HttpStatus.NO_CONTENT); } }
I've included imports just in case.
Anyway, if I change ReservationRequest to have fields with Strings instead of LocalDate like this then it doesn't produce error
public class ReservationRequest { private Long id; @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) private String checkin; @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) private String checkout; public ReservationRequest() { super(); } public ReservationRequest(Long id, String checkin, String checkout) { super(); this.id = id; this.checkin = checkin; this.checkout = checkout; } (getters and setters updated as well)
JDK 1.8; springBootVersion = '1.5.17.RELEASE'; name: 'jackson-datatype-jsr310', version: '2.9.7'
Question is why it doesn't work as intended with LocalDate?
UPDATE: tried these solutions, and added @JsonSerialize and @JsonDeserialize, as neither
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
orobjectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
worked so now it looks like:
public class ReservationRequest { private Long id; @JsonSerialize(using = ToStringSerializer.class) @JsonDeserialize(using = LocalDateDeserializer.class) //@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) private LocalDate checkin; @JsonSerialize(using = ToStringSerializer.class) @JsonDeserialize(using = LocalDateDeserializer.class) //@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) private LocalDate checkout; public ReservationRequest() { super(); }
So, now it looks like it works but I don't know if it is good solution?
-
Ole V.V. over 5 years
-
Nenad Bulatović over 5 yearsTried it - didn't help.
-