Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typed queries ignore @SerialName annotations on enum values, regression from 4.4.0 #331

Closed
krodyrobi opened this issue Mar 21, 2022 · 1 comment

Comments

@krodyrobi
Copy link

Description

The following code works on 4.4.0 but fails on 4.5.0 if a @SerialName annotation is provided with a custom name.

col.findOne(Foo::enum eq Enum.VALUE)
col.findOne(Filters.eq("enum", "<ValueSerialName>"))

From what I can tell string fields / custom serialization modules are respected but not for enums.
Not sure if only enums are affected though.

Steps to reproduce

plugins {
    kotlin("jvm") version "1.6.10"
    kotlin("plugin.serialization") version "1.6.10"
}

group = "org.example"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    implementation(kotlin("stdlib"))
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.5.2")
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2")
    implementation("org.litote.kmongo:kmongo-coroutine-serialization:4.5.0")
    implementation("de.flapdoodle.embed:de.flapdoodle.embed.mongo:3.2.4")
    implementation("ch.qos.logback:logback-classic:1.2.11")
}
import ch.qos.logback.classic.Level
import com.mongodb.client.model.Filters
import de.flapdoodle.embed.mongo.MongodStarter
import de.flapdoodle.embed.mongo.config.MongodConfig
import de.flapdoodle.embed.mongo.config.Net
import de.flapdoodle.embed.mongo.distribution.Version
import de.flapdoodle.embed.process.runtime.Network
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.modules.SerializersModule
import org.litote.kmongo.coroutine.CoroutineClient
import org.litote.kmongo.coroutine.coroutine
import org.litote.kmongo.eq
import org.litote.kmongo.reactivestreams.KMongo
import org.litote.kmongo.serialization.registerModule
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.net.InetAddress
import ch.qos.logback.classic.Logger as LogbackLogger

@Serializable
data class Jedi(
    @SerialName("Name")
    val name: String,
    val age: Int,
    val rating: Rating
)

@Serializable
enum class Rating {
    @SerialName("Favourite")
    FAVOURITE,

    @SerialName("Hated")
    HATED,
}

class Something

object SomethingSerializer : KSerializer<Something> {
    override fun deserialize(decoder: Decoder): Something {
        decoder.decodeString()
        return Something()
    }

    override fun serialize(encoder: Encoder, value: Something) = encoder.encodeString("FOO")

    override val descriptor: SerialDescriptor
        get() = PrimitiveSerialDescriptor("com.example.Something", PrimitiveKind.STRING)
}

fun setup(): CoroutineClient {
    val serializersModule = SerializersModule {
        contextual(Something::class, SomethingSerializer)
    }
    registerModule(serializersModule)

    val port = Network.freeServerPort(InetAddress.getLocalHost())
    val connectionString = "mongodb://localhost:$port"

    val starter = MongodStarter.getDefaultInstance()
    val mongoConfig = MongodConfig.builder()
        .version(Version.Main.PRODUCTION)
        .net(Net(port, false))
        .build()

    starter.prepare(mongoConfig).apply { start() }

    println("Embedded MongoDB created. Connect with: $connectionString.")
    return KMongo.createClient(connectionString).coroutine
}

fun main() {
    (LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME) as LogbackLogger).level = Level.ALL
    val client = setup()

    val database = client.getDatabase("test")
    val col = database.getCollection<Jedi>()

    runBlocking {
        col.insertOne(Jedi("Luke Skywalker", 19, Rating.FAVOURITE))
        col.insertOne(Jedi("FOO", 9001, Rating.HATED))

        // 13:27:06.399 [AsyncGetter-2-thread-1] DEBUG org.mongodb.driver.protocol.command - Sending command '{"find": "jedi", "filter": {"rating": "Favourite"}, "limit": 1, "singleBatch": true, "$db": "test", "lsid": {"id": {"$binary": {"base64": "1HzzXXesSIanIPH0Mc6X0A==", "subType": "04"}}}}' with request id 7 to database test on connection [connectionId{localValue:3, serverValue:3}] to server localhost:54880
        val jedi1: Jedi? = col.findOne(Jedi::rating eq Rating.FAVOURITE)
        println(jedi1) // 4.5.0 = null 4.4.0=Jedi(name=Luke Skywalker, age=19, rating=FAVOURITE)

        val jedi2: Jedi? = col.findOne(Filters.eq("rating", "Favourite"))
        println(jedi2) // both Jedi(name=Luke Skywalker, age=19, rating=FAVOURITE)

        val jedi3: Jedi? = col.findOne(Jedi::name eq "Luke Skywalker")
        println(jedi3) // both Jedi(name=Luke Skywalker, age=19, rating=FAVOURITE)

        val jedi4: Jedi? = col.findOne(Filters.eq("Name", "Luke Skywalker"))
        println(jedi4) // both Jedi(name=Luke Skywalker, age=19, rating=FAVOURITE)

        val jedi5: Jedi? = col.findOne(Filters.eq("Name", Something()))
        println(jedi5) // both Jedi(name=FOO, age=9001, rating=HATED)
    }
}
@zigzago
Copy link
Member

zigzago commented Mar 30, 2022

Thank you for reporting

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants