Quarkus: Kotlin data class not work without annotation

Created on 9 Dec 2019  路  18Comments  路  Source: quarkusio/quarkus

I try https://quarkus.io/guides/rest-json on kotlin. I want to use simple data class, without any annotation.

data class Fruit(
        val name : String,
        val description : String)

if I use quarkus-resteasy-jackson
(no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
If I use quarkus-resteasy-jsonb
I get No default constructor found.
This is bad practice to use default constructor in this case.
related topic

1.0.1.Final

arekotlin kinbug

Most helpful comment

Can you try with quarkus-resteasy-jackson and the Jackson kotlin module ?

<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-kotlin</artifactId>
</dependency>

All 18 comments

Can you try with quarkus-resteasy-jackson and the Jackson kotlin module ?

<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-kotlin</artifactId>
</dependency>

Like @loicmathieu says, adding jackson-module-kotlin should do the trick (and Quarkus we even add it automatically in version 1.1.x when the kotlin and jackson extensions are both present).
This is not a Quarkus limitation but stems from how Kotlin and Jackson interact, so I am going to close it. Feel free to reopen with more data if you still feel there is something that Quarkus should be doing.

This question looks more trick. I made some investigation. Add jackson-module-kotlin is not enough.
By default java and kotlin in runtime does not know about field name.
You should pass javac -parameters for compiler
Spring boot 2 in spring-boot-starter-parent set up it by default

 <plugin>
             <groupId>org.jetbrains.kotlin</groupId>
...
              <configuration>
                        <javaParameters>true</javaParameters>  
              </configuration>
</plugin>
<plugin>
              <artifactId>maven-compiler-plugin</artifactId>
              <configuration>
                        <parameters>true</parameters>
              </configuration>
</plugin>

If you add this parameter to quarkus, it will work with kotlin data class perfect.
### I suggest to change this behaviors in quarkus.
Here is example project

Moreover if you want to deserialize by hand, you need register ParameterNamesModule.
Look at code below

val jsonAsString ="{\"name\":\"a\",\"description\":\"description\"}";
val objectMapper = ObjectMapper();
// objectMapper.registerModule(ParameterNamesModule())
val readValue = objectMapper.readValue(jsonAsString, Fruit::class.java)

here is
(no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
But if I uncoment
objectMapper.registerModule(ParameterNamesModule())
that parse perfect.
So quarkus by default register this module.

Thanks for the analysis @serg-bs !

AFAIR we do add that module automatically, but I needs to be verified how it behaves with Kotlin, so I'll reopen the issue.

I have experienced a variant of this problem -- when I run a JUnit Quarkus test it fails, yet it works perfectly when not run through JUnit (for both JVM and Native).

Why would I experience different behaviour on a Unit test with Kotlin & Jackson for a data class?

I have experienced a variant of this problem -- when I run a JUnit Quarkus test it fails, yet it works perfectly when not run through JUnit (for both JVM and Native).

Why would I experience different behaviour on a Unit test with Kotlin & Jackson for a data class?

That is something totally new! I would like to have a reproducer for this if possible

Please see my unit tests in the repository below.

https://github.com/oztimpower/kotlin-lambda.git

Where it fails is where I've leveraged the Quarkus Lambda integration test, LambdaClient.invoke.

Thanks, I'll take a look

@oztimpower would you like to take a look at: https://github.com/quarkusio/quarkus/pull/7508 ?

With that change and this diff of pom.xml:

diff --git a/pom.xml b/pom.xml
index b1f33d5..569ee12 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,10 +13,10 @@
         <maven.compiler.target>1.8</maven.compiler.target>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-        <quarkus-plugin.version>1.2.1.Final</quarkus-plugin.version>
-        <quarkus.platform.artifact-id>quarkus-universe-bom</quarkus.platform.artifact-id>
+        <quarkus-plugin.version>999-SNAPSHOT</quarkus-plugin.version>
+        <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
         <quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
-        <quarkus.platform.version>1.2.1.Final</quarkus.platform.version>
+        <quarkus.platform.version>999-SNAPSHOT</quarkus.platform.version>
         <surefire-plugin.version>2.22.1</surefire-plugin.version>
     </properties>
     <dependencyManagement>
@@ -33,12 +33,8 @@
     <dependencies>
         <dependency>
             <groupId>io.quarkus</groupId>
-            <artifactId>quarkus-resteasy</artifactId>
+            <artifactId>quarkus-resteasy-jackson</artifactId>
         </dependency>
-<!--        <dependency>-->
-<!--            <groupId>io.quarkus</groupId>-->
-<!--            <artifactId>quarkus-resteasy-jackson</artifactId>-->
-<!--        </dependency>-->
         <dependency>
             <groupId>org.jetbrains.kotlin</groupId>
             <artifactId>kotlin-stdlib-jdk8</artifactId>

The tests pass

Hi @geoand
I'm having the same issue with quarkus-amazon-lambda
I tried to add com.fasterxml.jackson.module:jackson-module-kotlin with explicitly declared com.fasterxml.jackson.module.kotlin.jacksonObjectMapper as a bean, but it didn't help.

If I add quarkus-resteasy-jackson it solves the problem, but I don't need this dependency in the classpath, because I don't use Resteasy

Hi @miron4dev

You should be able to just use quarkus-kotlin and quarkus-jackson to solve the problem.
quarkus-resteasy-jackson shouldn't be necessary.

@geoand

Unfortunately, it didn't help. Please check the sample project https://github.com/miron4dev/quarkus-issue-6041

Seems like you are missing:

implementation("com.fasterxml.jackson.module:jackson-module-kotlin")

in your build.gradle.kts @miron4dev

@geoand

You're right. It will not work until I add Jackson Kotlin Extension and register it as a bean.
However, if I add the Jackson mapper like this https://github.com/miron4dev/quarkus-issue-6041/blob/master/src/main/kotlin/com/miron4dev/JacksonConfiguration.kt
then it will not create objectMapper and I have the same problem.

To make it work I should add an observer of the StartupEvent as it is described here https://quarkus.io/guides/cdi-reference#startup-event

The solution looks hacky, but works. Do you have any plans to make such injections more obvious, e.g. using a special annotation?

Thank you for help!

@miron4dev You are welcome!

As per your issues, please read: https://quarkus.io/guides/rest-json#jackson

I believe you will find all you need to make configuring Jackson super easy :)
I don't see us needing to add anything else to the already existing feature set - but if proven otherwise, I'd be glad to revisit.

@geoand

The trick with ObjectMapperCustomizer is not working. The customize method just not triggered.
I updated the sample project.

First of all, you don't need to configure anything when you add

implementation("com.fasterxml.jackson.module:jackson-module-kotlin")

like I mentioned above. Quarkus will automatically register this module when it's on the build classpath (and both quarkus-jackson and quarkus-kotlin are also present).

With the previous incarnation of your reproducer I was seeing module being registered just fine when I added the dependency.

Now as to the problem with customizer you mention, I'll look into it.

So the reason why you aren't seeing your ObjectMapperCustomizer run is because Quarkus believes that ObjectMapper bean is not being used at all (see this for more details).
This is a bug with Amazon Lamdba + Jackson integration which can be fixed very easily on our side (by making the bean unremovable like the quarkus-resteasy-jackson already does), but I know that @patriot1burke is working on a lot of improvements that include this one as well.

For now the workaround is to include quarkus-resteasy-jackson, but that won't be needed once we fix the bug.
Another potential workaround would be for you to inject ObjectMapper into one of your CDI beans (you don't need to use it, just inject it via field or constructor injection).

Thanks for reporting @miron4dev

Was this page helpful?
0 / 5 - 0 ratings