Leftwing
Leftwing

Reputation: 223

Using Spring @RestController with @QuerydslPredicate to handle GET With ZonedDateTime parameters

Im creating an endpoint that will receive dates to do some filtering on the serverside. The code looks like this:

@RequestMapping(value = "/invoices", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@Timed
public ResponseEntity<List<Invoice>> getAllInvoices(@QuerydslPredicate(root = Invoice.class) Predicate predicate, Pageable pageable) throws URISyntaxException {
    log.debug("REST request to get a page of Invoices");
    Page<Invoice> page = invoiceService.findAll(predicate, pageable);
    HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/invoices");
    return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
}

When I try to invoke the endpoint with this url: http://localhost:3000/api/invoices?page=0&size=20&sort=id,asc&sort=id&transactionDate=2016-05-09T22:00:00.000Z&transactionDate=2016-05-17T21:59:59.999Z

This exception is thrown:

java.time.format.DateTimeParseException: Text '2016-05-09T22:00:00.000Z' could not be parsed at index 10
    at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949) ~[na:1.8.0_91]
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851) ~[na:1.8.0_91]
    at java.time.ZonedDateTime.parse(ZonedDateTime.java:597) ~[na:1.8.0_91]
    at org.springframework.format.datetime.standard.TemporalAccessorParser.parse(TemporalAccessorParser.java:80) ~[spring-context-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.format.datetime.standard.TemporalAccessorParser.parse(TemporalAccessorParser.java:47) ~[spring-context-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.format.support.FormattingConversionService$ParserConverter.convert(FormattingConversionService.java:194) ~[spring-context-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:35) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:192) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.data.querydsl.binding.QuerydslPredicateBuilder.convertToPropertyPathSpecificType(QuerydslPredicateBuilder.java:217) ~[spring-data-commons-1.11.2.RELEASE.jar:na]
..... etc etc

Parsing the given dates works (on ideone.com) using just the ZonedDateTime object, but ok something else might be wrong. I found this question on SO: Using Spring @RestController to handle HTTP GET with ZonedDateTime parameters

@RequestMapping(value = "/invoices", params="action", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@Timed
public ResponseEntity<List<Invoice>> findInvoices(@RequestParam("dt") @DateTimeFormat(iso=ISO.DATE_TIME) ZonedDateTime dt,Pageable pageable) throws URISyntaxException {
    log.debug("REST request to get a page of Invoices");
    Page<Invoice> result = invoiceRepository.findAllByTransactionDate(dt,pageable);
    HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(result, "/api/invoices");
    return new ResponseEntity<>(result.getContent(), headers, HttpStatus.OK);
}

Requesting the url: localhost:8080/api/invoices?action=search&dt=2016-05-13T15:12:33.658Z Gives the desired effect..

The obvious difference is the @DateTimeFormat(iso=ISO.DATE_TIME) addition to the requestparam. Now I'm wondering; how do i actually get that to work with the QueryDslPredicateBuilder? Should I somehow typehint the format?

Upvotes: 4

Views: 5374

Answers (1)

Leftwing
Leftwing

Reputation: 223

When looking for a different aspect of using querydsl parameter binding (using > x > kind of comparison) I ran into the following post: Can Spring Data REST's QueryDSL integration be used to perform more complex queries?

One of the answers hinted the following:

Make sure you add the @DateTimeFormat annotation to the dateOfBirth-property of User so that Spring is able to convert the incoming Strings into LocalDate instances correctly.

Which is the solution to my problem. I've added the @DateTimeFormat annotation to my Model such that:

@DateTimeFormat(iso = ISO.DATE_TIME) 
@Column(name = "transaction_date")
private ZonedDateTime transactionDate;

And voila, it works.

Upvotes: 3

Related Questions