Reputation: 6244
I'm using Spring Boot 1.5.3, Spring Data REST, Spring JPA, Hibernate. I'm working in UTC with java.time.* in the server, and my clients are supposed to send back dates in UTC too. I customized a bit my REST configuration:
@Configuration
public class RestConfig extends RepositoryRestConfigurerAdapter {
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return new Jackson2ObjectMapperBuilderCustomizer() {
@Override
public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
jacksonObjectMapperBuilder.serializers(InstantSerializer.INSTANCE);
jacksonObjectMapperBuilder.serializers(new ZonedDateTimeSerializer(ISO_FIXED_FORMAT));
jacksonObjectMapperBuilder
.serializers(new LocalDateSerializer(new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd").toFormatter()));
jacksonObjectMapperBuilder.serializers(new LocalDateTimeSerializer(
new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd'T'HH:mm:ss'Z'").toFormatter()));
}
};
}
}
I created a custom method in a repository:
@Transactional
@PreAuthorize("isAuthenticated()")
public interface DailyCodeRepository extends PagingAndSortingRepository<DailyCode, Long> {
@Query("SELECT d FROM DailyCode d WHERE (:code IS NULL OR code=:code) AND (:from IS NULL OR date>=:from) AND (:to IS NULL OR date<=:to)")
public Page<DailyCode> findAllWithParameter(@Param("code") @RequestParam(value = "code", required = false) String code,
@Param("from") @RequestParam(value = "from", required = false) @DateTimeFormat(iso=ISO.DATE) LocalDate from,
@Param("to") @RequestParam(value = "to", required = false) @DateTimeFormat(iso=ISO.DATE) LocalDate to, Pageable pageable);
}
The first problem is that the method accept the ISO format only if I put the annotation @DateTimeFormat(iso=ISO.DATE)
, otherwise it picks the format of my locale (Italy). I want to set it globally as done for the response (see my Jackson2ObjectMapperBuilderCustomizer).
The second problem is that date parameters sent from the client are interpreted like 1 day before, so a request like this:
http://localhost:8080/api/v1/dailyCodes/search/findAllWithParameter?from=2017-07-07&to=2017-07-07
causes this query on the database:
select dailycode0_.`id` as id1_7_, dailycode0_.`created_by` as created_2_7_, dailycode0_.`created_date` as created_3_7_, dailycode0_.`last_modified_by` as last_mod4_7_, dailycode0_.`last_modified_date` as last_mod5_7_, dailycode0_.`sid` as sid6_7_, dailycode0_.`version` as version7_7_, dailycode0_.`code` as code8_7_, dailycode0_.`date` as date9_7_ from `daily_code` dailycode0_ where (null is null or dailycode0_.`code`=null) and ('2017-07-06' is null or dailycode0_.`date`>='2017-07-06') and ('2017-07-06' is null or dailycode0_.`date`<='2017-07-06') limit 20
So it queries 1 day before and it's wrong. I guess it's a timezone problem but I can't figure out how to solve that.
This is the relevant part of my properties file:
spring.mvc.date-format= `yyyy-MM-dd`
# REST
spring.data.rest.default-page-size= 20
spring.data.rest.base-path=/api/v1
spring.data.rest.enable-enum-translation=true
#Jackson
# to avoid an error loading lazy objects
spring.jackson.serialization.fail-on-empty-beans=false
spring.jackson.serialization.write-dates-as-timestamps=false
spring.jackson.mapper.infer-property-mutators=false
spring.jpa.properties.hibernate.jdbc.time_zone = UTC
Upvotes: 0
Views: 1363
Reputation: 24528
You've several issues in your code:
The first problem is that the method accept the ISO format only
You need a OffsetDateTime
(not ZonedDateTime
, read this) and custom converter. Read this.
date parameters sent from the client are interpreted like 1 day before
Why? What time zone are you interpreting this date for? Your local time zone may be different from the server's which may be different from the client's.
Jackson2ObjectMapperBuilderCustomizer
What's this used for?
spring.mvc.date-format=yyyy-MM-dd
This shouldn't be necessary, and I don't think does anything for Spring data anyway.
Upvotes: 1