diff --git a/bson-kotlin/src/main/kotlin/org/bson/codecs/kotlin/DataClassCodec.kt b/bson-kotlin/src/main/kotlin/org/bson/codecs/kotlin/DataClassCodec.kt index 9027bec4574..412a0483231 100644 --- a/bson-kotlin/src/main/kotlin/org/bson/codecs/kotlin/DataClassCodec.kt +++ b/bson-kotlin/src/main/kotlin/org/bson/codecs/kotlin/DataClassCodec.kt @@ -23,12 +23,14 @@ import kotlin.reflect.KParameter import kotlin.reflect.KProperty1 import kotlin.reflect.KType import kotlin.reflect.KTypeParameter +import kotlin.reflect.KTypeProjection import kotlin.reflect.full.createType import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.findAnnotations import kotlin.reflect.full.hasAnnotation import kotlin.reflect.full.primaryConstructor import kotlin.reflect.jvm.javaType +import kotlin.reflect.jvm.jvmErasure import org.bson.BsonReader import org.bson.BsonType import org.bson.BsonWriter @@ -199,7 +201,7 @@ internal data class DataClassCodec( codecRegistry.getCodec( kParameter, (kParameter.type.classifier as KClass).javaObjectType, - kParameter.type.arguments.mapNotNull { typeMap[it.type] ?: it.type?.javaType }.toList()) + kParameter.type.arguments.mapNotNull { typeMap[it.type] ?: computeJavaType(it) }.toList()) } is KTypeParameter -> { when (val pType = typeMap[kParameter.type] ?: kParameter.type.javaType) { @@ -219,6 +221,13 @@ internal data class DataClassCodec( "Could not find codec for ${kParameter.name} with type ${kParameter.type}") } + private fun computeJavaType(kTypeProjection: KTypeProjection): Type? { + val javaType: Type = kTypeProjection.type?.javaType!! + return if (javaType == Any::class.java) { + kTypeProjection.type?.jvmErasure?.javaObjectType + } else javaType + } + @Suppress("UNCHECKED_CAST") private fun CodecRegistry.getCodec(kParameter: KParameter, clazz: Class, types: List): Codec { val codec = diff --git a/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/DataClassCodecProviderTest.kt b/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/DataClassCodecProviderTest.kt index e0c7f9d1d1b..7b9e0bbb2ba 100644 --- a/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/DataClassCodecProviderTest.kt +++ b/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/DataClassCodecProviderTest.kt @@ -20,11 +20,22 @@ import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertNull import kotlin.test.assertTrue +import kotlin.time.Duration +import org.bson.BsonReader +import org.bson.BsonWriter +import org.bson.codecs.Codec +import org.bson.codecs.DecoderContext +import org.bson.codecs.EncoderContext import org.bson.codecs.configuration.CodecConfigurationException +import org.bson.codecs.configuration.CodecRegistries.fromCodecs +import org.bson.codecs.configuration.CodecRegistries.fromProviders +import org.bson.codecs.configuration.CodecRegistries.fromRegistries import org.bson.codecs.kotlin.samples.DataClassParameterized +import org.bson.codecs.kotlin.samples.DataClassWithJVMErasure import org.bson.codecs.kotlin.samples.DataClassWithSimpleValues import org.bson.conversions.Bson import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.api.assertThrows class DataClassCodecProviderTest { @@ -59,4 +70,23 @@ class DataClassCodecProviderTest { assertTrue { codec is DataClassCodec } assertEquals(DataClassWithSimpleValues::class.java, codec.encoderClass) } + + @Test + fun shouldBeAbleHandleDataClassWithJVMErasure() { + + class DurationCodec : Codec { + override fun encode(writer: BsonWriter, value: Duration, encoderContext: EncoderContext) = TODO() + override fun getEncoderClass(): Class = Duration::class.java + override fun decode(reader: BsonReader, decoderContext: DecoderContext): Duration = TODO() + } + + val registry = + fromRegistries( + fromCodecs(DurationCodec()), fromProviders(DataClassCodecProvider()), Bson.DEFAULT_CODEC_REGISTRY) + + val codec = assertDoesNotThrow { registry.get(DataClassWithJVMErasure::class.java) } + assertNotNull(codec) + assertTrue { codec is DataClassCodec } + assertEquals(DataClassWithJVMErasure::class.java, codec.encoderClass) + } } diff --git a/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/samples/DataClasses.kt b/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/samples/DataClasses.kt index eaa87ca603b..029b0814118 100644 --- a/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/samples/DataClasses.kt +++ b/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/samples/DataClasses.kt @@ -15,6 +15,7 @@ */ package org.bson.codecs.kotlin.samples +import kotlin.time.Duration import org.bson.BsonDocument import org.bson.BsonMaxKey import org.bson.BsonType @@ -159,3 +160,5 @@ data class DataClassWithFailingInit(val id: String) { } data class DataClassWithSequence(val value: Sequence) + +data class DataClassWithJVMErasure(val duration: Duration, val ints: List)