quarkus: Cannot deserialize LocalDate in @QueryParam due to missing ParamConverterProvider

Describe the bug I’m using Jackson (via quarkus-resteasy-jackson) as ObjectMapper with the KotlinModule and the JavaTimeModule registered using an ObjectMapperCustomizer. When I have an endpoint with a @QueryParam of type LocalDate quarkus does not start.

Expected behavior I expect resteasy to use the provided ObjectMapper to deserialize a String formated “YYYY-MM-DD” into an instance of LocalDate.

Actual behavior Omitting the name and method signature for brevity I get

RESTEASY003875: Unable to find a constructor that takes a String param or a valueOf() or fromString() method for javax.ws.rs.QueryParam("adate") for basetype: java.time.LocalDate

To Reproduce Steps to reproduce the behavior:

  1. Use
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy-jackson</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.module</groupId>
            <artifactId>jackson-module-kotlin</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
        </dependency>
  1. Register a resource like
@GET
@Path("path")
fun broken( @QueryParam("adate") aDate: LocalDate) {}
  1. Run a @QuarkusTest to try a start up the application.

Environment (please complete the following information):

  • Output of uname -a or ver: Linux ninja-cgd 5.3.0-23-generic #25-Ubuntu SMP Tue Nov 12 09:22:33 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
  • Output of java -version: openjdk version “11.0.5-ea” 2019-10-15 OpenJDK Runtime Environment (build 11.0.5-ea+10-post-Ubuntu-0ubuntu1) OpenJDK 64-Bit Server VM (build 11.0.5-ea+10-post-Ubuntu-0ubuntu1, mixed mode, sharing)
  • GraalVM version (if different from Java): not used
  • Quarkus version or git rev: 0.25.0 Additional context

The problem is fixed by adding

@Provider
class LocalDateConverter : ParamConverterProvider {

    override fun <T: Any?> getConverter(rawType: Class<T>?, genericType: Type?, annotations: Array<out Annotation>?): ParamConverter<T>? {
        return if (rawType == LocalDate::class.java) {
            object: ParamConverter<T> {
                val mapper = ObjectMapper().also { JacksonObjectMapperCustomizer().customize(it) }
                override fun toString(value: T?): String {
                    return mapper.writeValueAsString(value)
                }
                override fun fromString(value: String?): T {
                    return mapper.readValue(value, LocalDate::class.java) as T
                }
            }
        } else null
    }
}

to the project. I was expecting that this kind of Provider would be added out of the box when using Jackson’s JavaTimeModule.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 1
  • Comments: 41 (33 by maintainers)

Commits related to this issue

Most upvoted comments

@geoand The " is part of the JSON. 2019-01-01 is invalid; it has to be "2019-01-01". See https://www.json.org/json-en.html

Thanks. I’ll take a look tomorrow or Friday

@geoand Yes, can do that with your help & guidance.

Well TBH it doesn’t make sense to me to have to expect the query string to contain quotes. Sure the converter could add them, but that doesn’t feel natural.

You mentioned that Spring does this as well, do you mind point me to this feature in Spring that utilizes Jackson? I wasn’t aware of it.

I have a different idea, we can just use objectMapper.convertValue 😉 . I tried it and it see to work fine, WDYT?

That way the user can just use 2019-01-01 without having to add the uggly quotes (remember that they don’t care if it’s JSON or not - it’s just a query param).

Interesting, so that means that you expect users to input "2019-01-01" as query param?

When using I do objectMapper.readValue(value, LocalDate.class) with 2019-01-01 being the value

Unexpected character ('-' (code 45)): Expected space separating root-level values