drenda
drenda

Reputation: 6244

Spring MVC LocalDate parameter has wrong format

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

Answers (1)

Abhijit Sarkar
Abhijit Sarkar

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

Related Questions