1

I set up a Spring Microservice app with a POST endpoint which takes in a RequestBody object which contains a 'java.util.Date' field. From my other app, when I send a request to this POST endpoint, the Date in the JSON looks good, in the format "2019-06-20T13:33:47.487-07:00", but when my microservice receives the request, it converts the Date String into the following: "Jun 20, 2019 1:33:47 PM" and tells me "Cannot deserialize value of type java.util.Date from String "Jun 20, 2019 1:33:47 PM": not a valid representation".

I've played around with different annotations, including "@Temporal(TemporalType.TIMESTAMP)" and "@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)". Also tried setting JSONFormat manually, but that isn't a fix, since the input date string is getting reinterpreted somehow somewhere.

Here's the microservice POST endpoint:

@PostMapping(path = "/orders/create")
public ResponseEntity createOrder(@RequestBody final HubOrder hubOrder) {
    List<OrderLineitem> orderLineitem = orderService.hubOrderToOrderLineitems(hubOrder);
    repository.saveAll(orderLineitem);
    return ResponseEntity.created().build();
}

And bean:

@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class HubOrder {
    private BigInteger id; 
    private Date created; 
    private String lastModifiedBy; 
    private List<HubLineitem> lineitems;
}

And I hit the endpoint from my app like so:

HubOrder hubOrder = createHubOrderFromOrder(order);
Gson gson = new Gson();
HttpPost request = new HttpPost("http://localhost:8888/orders/create");
StringEntity params = new StringEntity(gson.toJson(hubOrder));
HttpClient httpClient = HttpClientBuilder.create().build();


request.addHeader("content-type", "application/json");
request.setEntity(params);
HttpResponse response = httpClient.execute(request);

Where hubOrder.getCreated() == "2019-06-20T13:33:47.487-07:00"

The error from my microservice is "2019-07-08 20:50:47.663 WARN 2400 --- [nio-8888-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type java.util.Date from String "Jun 20, 2019 1:33:47 PM": not a valid representation (error: Failed to parse Date value 'Jun 20, 2019 1:33:47 PM': Unparseable date: "Jun 20, 2019 1:33:47 PM"); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type java.util.Date from String "Jun 20, 2019 1:33:47 PM": not a valid representation (error: Failed to parse Date value 'Jun 20, 2019 1:33:47 PM': Unparseable date: "Jun 20, 2019 1:33:47 PM") "

P_equals_NP_2021
  • 627
  • 1
  • 9
  • 27
  • create a custom `deserializer` and try using single format if possible. and have you tried this? https://stackoverflow.com/questions/17655532/json-serializing-date-in-a-custom-format-can-not-construct-instance-of-java-uti – bananas Jul 09 '19 at 05:00
  • No, I'm trying to figure out why it's deserializing wrong in the first place. – P_equals_NP_2021 Jul 09 '19 at 22:13

2 Answers2

1

Please try to annotate your Date created field in HubOrder with the following;

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "MMM dd, yyyy hh:mm:ss aaa")
private Date created

Deserialization expects in different formats by default depending on configuration, and it seems your locale affects it, as described here. To customize the behaviour, you'd have to utilize the above annotation. Or to apply this for all cases do the following;

  • either instantiate gson with the pattern as follows;

    Gson gson = new GsonBuilder()
        .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
        .create();
    
  • or pass a custom adapter for Date types

    public class GsonDateAdapter implements JsonSerializer<Date>,JsonDeserializer<Date> {
    
        private final DateFormat dateFormat;
    
        public GsonUTCDateAdapter() {
          dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        }
    
        @Override public synchronized JsonElement serialize(Date date,Type type,JsonSerializationContext jsonSerializationContext) {
            return new JsonPrimitive(dateFormat.format(date));
        }
    
        @Override public synchronized Date deserialize(JsonElement jsonElement,Type type,JsonDeserializationContext jsonDeserializationContext) {
          try {
            return dateFormat.parse(jsonElement.getAsString());
          } catch (ParseException e) {
            throw new JsonParseException(e);
          }
        }
    }
    

    then

    Gson gson = new GsonBuilder()
                   .registerTypeAdapter(Date.class, new GsonDateAdapter())
                   .create();
    
buræquete
  • 14,226
  • 4
  • 44
  • 89
  • Tried this, but getting "Cannot deserialize value of type `java.util.Date` from String "Jun 20, 2019 1:33:47 PM": expected format "yyyy-MM-dd'T'HH:mm:ss.SSSZ";" – P_equals_NP_2021 Jul 09 '19 at 04:14
  • Debugging the POJO that gets sent as the body, created="2019-06-20T13:33:47.487-07:00" – P_equals_NP_2021 Jul 09 '19 at 04:16
  • Debugging might use default `.toString()` which might not be what the original value is in raw JSON, which seems to be different as you've shared... – buræquete Jul 09 '19 at 04:17
  • I added an extra doublecheck where I do "Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").parse(lineItem.getCreated().toString());" – P_equals_NP_2021 Jul 09 '19 at 04:17
  • In that case it works, but I wanted to try to fix the date format becoming like that automatically in my microservice... – P_equals_NP_2021 Jul 09 '19 at 04:33
  • @TDaddy The problem was when you try to serialize the result with `gson.toJson(hubOrder)`, here it was mapping to that pattern somehow, maybe it was configured that way? You can try to control that with [this](https://stackoverflow.com/questions/6873020/gson-date-format). You can set `yyyy-MM-dd'T'HH:mm:ss.SSSZ` as the default pattern for gson, thus it would work properly I think... – buræquete Jul 09 '19 at 04:49
1

you should write function setCreated() and see the input, after that using jsonFormat to convert it :D