javakotlinjava-timehttp-request-parameters

Is possible to use LocalDateTime as a RequestParam in Kotlin?


I'm learning Kotlin, doing a simple API Rest with Spring Boot. My problem is that I'm trying to use LocalDateTime as @RequestParam but it just not working as it does in Java. This is my code:

import org.springframework.format.annotation.DateTimeFormat
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import java.time.LocalDateTime

@RestController
@RequestMapping("/flights")
class FlightController(private val flightService : FlightService) {

    @GetMapping
    fun getFlights(@RequestParam @DateTimeFormat(pattern = "hh:mma") departure : LocalDateTime?): List<Flight> {
        return flightService.getFlights()
    }
}

When I do an HTTP call this is the error I see in the console:

Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.time.LocalDateTime'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam @org.springframework.format.annotation.DateTimeFormat java.time.LocalDateTime] for value '09:00am'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [09:00am]]

(In this case, I tried 09:00am as RequestParam)

I think it is a problem with Jackson not being able to parse the JSON to LocalDateTime, anybody knows if there is a solution? Thank you guys

(Edited)

Here is the full stacktrace:

OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.1)

2021-06-18 11:34:42.650  INFO 16396 --- [           main] c.e.f.FlightsKotlinApplicationKt         : Starting FlightsKotlinApplicationKt using Java 16.0.1 on ar-it14622 with PID 16396
2021-06-18 11:34:42.652  INFO 16396 --- [           main] c.e.f.FlightsKotlinApplicationKt         : No active profile set, falling back to default profiles: default
2021-06-18 11:34:43.238  INFO 16396 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2021-06-18 11:34:43.293  INFO 16396 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 46 ms. Found 1 JPA repository interfaces.
2021-06-18 11:34:43.689  INFO 16396 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2021-06-18 11:34:43.696  INFO 16396 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-06-18 11:34:43.696  INFO 16396 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.46]
2021-06-18 11:34:43.838  INFO 16396 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-06-18 11:34:43.839  INFO 16396 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1145 ms
2021-06-18 11:34:43.971  INFO 16396 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2021-06-18 11:34:44.009  INFO 16396 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 5.4.32.Final
2021-06-18 11:34:44.104  INFO 16396 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
2021-06-18 11:34:44.183  INFO 16396 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2021-06-18 11:34:44.440  INFO 16396 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2021-06-18 11:34:44.464  INFO 16396 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL8Dialect
2021-06-18 11:34:44.780  INFO 16396 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2021-06-18 11:34:44.788  INFO 16396 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2021-06-18 11:34:45.092  WARN 16396 --- [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2021-06-18 11:34:45.396  INFO 16396 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2021-06-18 11:34:45.404  INFO 16396 --- [           main] c.e.f.FlightsKotlinApplicationKt         : Started FlightsKotlinApplicationKt in 3.084 seconds (JVM running for 3.901)
2021-06-18 11:34:54.426  INFO 16396 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-06-18 11:34:54.426  INFO 16396 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2021-06-18 11:34:54.427  INFO 16396 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
2021-06-18 11:34:54.484  WARN 16396 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.time.LocalDateTime'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam @org.springframework.format.annotation.DateTimeFormat java.time.LocalDateTime] for value '09:00am'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [09:00am]]

And my build.gradle.kts (maybe can be helpful):

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.ir.backend.js.compile

plugins {
    id("org.springframework.boot") version "2.5.1"
    id("io.spring.dependency-management") version "1.0.11.RELEASE"
    kotlin("jvm") version "1.5.10"
    kotlin("plugin.spring") version "1.5.10"
    kotlin("plugin.jpa") version "1.5.10"
}

group = "com.learning"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_16

configurations {
    compileOnly {
        extendsFrom(configurations.annotationProcessor.get())
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter")
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    implementation("org.apache.logging.log4j:log4j-api-kotlin:1.0.0")
    implementation("org.apache.logging.log4j:log4j-api:2.11.1")
    implementation("org.apache.logging.log4j:log4j-core:2.11.1")
    runtimeOnly("mysql:mysql-connector-java")
    annotationProcessor("org.projectlombok:lombok")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
    implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.5")
}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs = listOf("-Xjsr305=strict")
        jvmTarget = "16"
    }
}

tasks.withType<Test> {
    useJUnitPlatform()
}

Solution

  • A time-of-day alone is not enough information to instantiate a LocalDateTime. That class represents a date with a time-of-day. You are missing the date portion.

    You commented that you tried using LocalTime but failed. I am guessing that your string inputs do not match the format used for the AM/PM indicators expected by by your JVM’s current default Locale. Various cultures may use “am”, “AM”, “A.M.”, or something else. Solutions include:

    I suggest you practice using the java.time classes in some simple throwaway code, without the complexities of Spring.

    Date-time handling is not as simple and trivial a matter as you may intuit. Indeed, your intuitive quotidian understanding of date-time is a hindrance, such as leading you to use to AM/PM rather than using 24-hour clock. Take time to search Stack Overflow to learn more about java.time classes.