Wim Deblauwe
Wim Deblauwe

Reputation: 26858

List of ZonedDateTime as request body with Spring

I'm implementing a Spring @RestController with a @PostMapping annotated method. I want to allow a HTTP POST using this body:

{"dateTimes":[
  "2017-07-19T14:25+02:00",
  "2017-08-19T14:25+02:00"
]
}

I have an object used as @RequestBody:

public class TransactionAllowedRequestBody {
  @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
  private List<ZonedDateTime> dateTimes;

  public List<ZonedDateTime> getDateTimes() {
    return dateTimes;
  }


  public void setDateTimes(List<ZonedDateTime> dateTimes) {
    this.dateTimes = dateTimes;
  }
}

This is my controller method:

@PostMapping("/transaction-allowed")
public void isTransactionAllowed(@AuthenticationPrincipal CustomUserDetails userDetails,
                                 @RequestBody TransactionAllowedRequestBody requestBody) {
    System.out.println("requestBody = " + requestBody);
}

However, when I try this, I get:

Could not read JSON document: Can not construct instance of java.time.ZonedDateTime: 
no String-argument constructor/factory method to deserialize from String value ('2017-07-19T14:25+02:00')

If I replace ZonedDateTime with String, it works.

I am using Spring Boot 1.5.3.

Note: Using @DateTimeFormat on a GET request parameter works fine. I tried it with:

@GetMapping("/transaction-allowed")
public void isTransactionAllowed(@AuthenticationPrincipal CustomUserDetails userDetails,
                                 @RequestParam("datetime") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime dateTime) {
    System.out.println("userDetails = " + userDetails);
    System.out.println("dateTime = " + dateTime);
}

Upvotes: 0

Views: 2296

Answers (2)

Nur Zico
Nur Zico

Reputation: 2447

You can use @JsonDeserialize and a Deserializer of your own

Like the following one

public class ZonedDateTimeDeserializer extends JsonDeserializer<List<ZonedDateTime>> {
    @Override
    public List<ZonedDateTime> deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        ObjectCodec oc = jp.getCodec();
        JsonNode array = oc.readTree(jp);
        List<ZonedDateTime> dates = new ArrayList<>();
        if(array.isArray()) {
            for (JsonNode node: array) {
                dates.add(ZonedDateTime.parse(node.asText()));
            }
        }
        return dates;
    }
}

To use the Deserializer annotation will be like

@JsonDeserialize(using = ZonedDateTimeDeserializer.class)
private List<ZonedDateTime> dateTimes;

Upvotes: 0

Wim Deblauwe
Wim Deblauwe

Reputation: 26858

Seems the issue was that I forget to include the jackson-datatype-jsr310 dependency as Spring Boot will not add it by default:

    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>${jackson.version}</version>
    </dependency>

Upvotes: 1

Related Questions