In KotlinSerializationSupport:

    @Nullable
    protected final KSerializer<Object> serializer(ResolvableType resolvableType) {
        Type type = resolvableType.getType();
        KSerializer<Object> serializer = serializerCache.get(type);
        if (serializer == null) {
            try {
                serializer = SerializersKt.serializerOrNull(type);
            }
            catch (IllegalArgumentException ignored) {
            }
            if (serializer != null) {
                if (hasPolymorphism(serializer.getDescriptor(), new HashSet<>())) {
                    return null;
                }
                serializerCache.put(type, serializer);
            }
        }
        return serializer;
    }

the call serializer = SerializersKt.serializerOrNull(type); generates an instance of EmptySerializersModule() which - by definition - does not contain any information about custom serializers. Using format.getSerializersModule().serializerOrNull() would allow the Kotlin serialization in WebFlux to use custom serializers for third-party classes as is possible for WebMVC's Kotlin serialization implementation.

Comment From: sdeleuze

Thanks for raising this, I tend to think it makes sense. From Java format.getSerializersModule().serializerOrNull() looks innaccessible but SerializersKt.serializerOrNull(format.getSerializersModule(), type) is.

Any simple repro available?

Comment From: severn-everett

Here's a repro of the two different serializerOrNull() calls using Kotlinx Serialization and Spring Core:

import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.serializerOrNull
import org.springframework.core.ResolvableType
import java.math.BigDecimal

object BigDecimalSerializer : KSerializer<BigDecimal> {
    override val descriptor = PrimitiveSerialDescriptor("BigDecimal", PrimitiveKind.DOUBLE)

    override fun deserialize(decoder: Decoder): BigDecimal = BigDecimal.valueOf(decoder.decodeDouble())

    override fun serialize(encoder: Encoder, value: BigDecimal) {
        encoder.encodeDouble(value.toDouble())
    }
}

fun main() {
    val bigDecimalType = ResolvableType.forClass(BigDecimal::class.java)
    val json = Json {
        serializersModule = SerializersModule {
            contextual(BigDecimal::class, BigDecimalSerializer)
        }
    }
    val bdType = bigDecimalType.type
    val defaultSerializer = serializerOrNull(bdType)
    val jsonSerializer = json.serializersModule.serializerOrNull(bdType)
    println("SERIALIZERS: $defaultSerializer | $jsonSerializer")
}