quarkus: When using kotlin with mongo panache, the deserializer fails unless all the constructor parameters are declared as nullable or have a default value

The title is pretty much self explanatory. When using a kotlin class that extends PanacheMongoEntity unless the fields are declared as nullable or have default values the deserialization when doing any find operation (e.g. listAll()) fails with the following error:

Caused by: org.bson.codecs.configuration.CodecConfigurationException: Cannot find a public constructor for 'ChargingInterval'.
	at org.bson.codecs.pojo.CreatorExecutable.checkHasAnExecutable(CreatorExecutable.java:140)
	at org.bson.codecs.pojo.CreatorExecutable.getInstance(CreatorExecutable.java:107)
	at org.bson.codecs.pojo.InstanceCreatorImpl.<init>(InstanceCreatorImpl.java:40)
	at org.bson.codecs.pojo.InstanceCreatorFactoryImpl.create(InstanceCreatorFactoryImpl.java:28)
	at org.bson.codecs.pojo.ClassModel.getInstanceCreator(ClassModel.java:71)
	at org.bson.codecs.pojo.PojoCodecImpl.decode(PojoCodecImpl.java:120)
	at org.bson.codecs.pojo.PojoCodecImpl.decode(PojoCodecImpl.java:125)
	at org.bson.codecs.pojo.AutomaticPojoCodec.decode(AutomaticPojoCodec.java:37)

Sample failing class:

package io.biapower.services.chargingsessionservice.domain
import io.quarkus.mongodb.panache.PanacheMongoEntity
import java.time.Instant

data class SampleDataClass(
        var start: Instant = Instant.now(),
        var end: Instant,
        var num: Int = 0f
): PanacheMongoEntity()

Sample working class:

package io.biapower.services.chargingsessionservice.domain
import io.quarkus.mongodb.panache.PanacheMongoEntity
import java.time.Instant

data class SampleDataClass(
        var start: Instant = Instant.now(),
        var end: Instant = Instant.now(),
        var num: Int = 0
): PanacheMongoEntity()

or:

package io.biapower.services.chargingsessionservice.domain
import io.quarkus.mongodb.panache.PanacheMongoEntity
import java.time.Instant

data class SampleDataClass(
        var start: Instant = Instant.now(),
        var end: Instant? = null,
        var num: Int = 0
): PanacheMongoEntity()

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 15 (10 by maintainers)

Commits related to this issue

Most upvoted comments

@TheVidAllMayThe when writing the documentation part (#6877 ) two questions arises. If you can try the following and provide feedback this would be great :

  • Is the @BsonCreator approach works in native mode ?
  • Did you try the Kotlin no-arg compiler plugin instead of using the @BsonCreator

@gsmet @TheVidAllMayThe using the no-arg compiler plugin and the not mandatory @MongoEntity annotation (as the compiler plugin needs an anotation to target classes that needs a no-arg constructor) it works.

@MongoEntity
data class SampleFailingDataClass (
        var sampleString: String = "",
        var sampleInteger: Int
): PanacheMongoEntity()

I tested native mode and it works for both approach.

I will update the guide acordingly and close this issue.

@TheVidAllMayThe this is not a Quarkus MongoDB with Panache issue but it’s a limitation of Kotlin dataclass with frameworks that needs an empty constructor. We use MongoDB automatic pojo codec to serialize to/from the database and it needs an empty constructor.

There is multiple way to fix the issue:

  1. Add default values to all the field of your data class to generates an empty constructor. See this sentence from the Kotlin documentation :

On the JVM, if the generated class needs to have a parameterless constructor, default values for all properties have to be specified (see Constructors).

  1. Create a BSON Codec, it will be automatically registered by Quarkus and will be used instead of the automatic pojo codec: https://quarkus.io/guides/mongodb#simplifying-mongodb-client-usage-using-bson-codec

  2. Use the @BsonCreator annotation to tell the MongoDB automatic pojo codec to use the Kotlin dataclass default constructor, in this case all fields needs to be annotated with @BsonProperty: https://mongodb.github.io/mongo-java-driver/3.12/bson/pojos/#supporting-pojos-without-no-args-constructors

Updating the SampleFailingDataClass with the @BsonCreator annotation make the sample application working.

data class SampleFailingDataClass @BsonCreator constructor (
        @BsonProperty("sampleString") var sampleString: String = "",
        @BsonProperty("sampleInteger") var sampleInteger: Int
): PanacheMongoEntity()

If it’s OK, I propose to add a section on the MongoDB with Panache guide explaining how to use Kotlin dataclass with the MongoDB automatic pojo codec.