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..5431a765d48 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 @@ -18,17 +18,19 @@ package org.bson.codecs.kotlin import java.lang.reflect.ParameterizedType import java.lang.reflect.Type import kotlin.reflect.KClass +import kotlin.reflect.KClassifier import kotlin.reflect.KFunction 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 @@ -140,7 +142,9 @@ internal data class DataClassCodec( val primaryConstructor = kClass.primaryConstructor ?: throw CodecConfigurationException("No primary constructor for $kClass") val typeMap = - types.mapIndexed { i, k -> primaryConstructor.typeParameters[i].createType() to k }.toMap() + types + .mapIndexed { i, k -> primaryConstructor.typeParameters[i].createType().classifier!! to k } + .toMap() val propertyModels = primaryConstructor.parameters.map { kParameter -> @@ -191,7 +195,7 @@ internal data class DataClassCodec( @Suppress("UNCHECKED_CAST") private fun getCodec( kParameter: KParameter, - typeMap: Map, + typeMap: Map, codecRegistry: CodecRegistry ): Codec { return when (kParameter.type.classifier) { @@ -199,10 +203,12 @@ 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?.classifier] ?: computeJavaType(it) } + .toList()) } is KTypeParameter -> { - when (val pType = typeMap[kParameter.type] ?: kParameter.type.javaType) { + when (val pType = typeMap[kParameter.type.classifier] ?: kParameter.type.javaType) { is Class<*> -> codecRegistry.getCodec(kParameter, (pType as Class).kotlin.javaObjectType, emptyList()) is ParameterizedType -> @@ -219,6 +225,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/DataClassCodecTest.kt b/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/DataClassCodecTest.kt index d2dbfc580cc..40abc3a9cfa 100644 --- a/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/DataClassCodecTest.kt +++ b/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/DataClassCodecTest.kt @@ -249,7 +249,7 @@ class DataClassCodecTest { |"nestedParameterized": { | "parameterizedDataClass": | {"number": 4.2, "string": "myString", "parameterizedList": [{"name": "embedded1"}]}, - | "other": "myOtherString" + | "other": "myOtherString", "optionalOther": "myOptionalOtherString" | } |}""" .trimMargin() @@ -257,7 +257,9 @@ class DataClassCodecTest { DataClassWithNestedParameterizedDataClass( "myId", DataClassWithNestedParameterized( - DataClassParameterized(4.2, "myString", listOf(DataClassEmbedded("embedded1"))), "myOtherString")) + DataClassParameterized(4.2, "myString", listOf(DataClassEmbedded("embedded1"))), + "myOtherString", + "myOptionalOtherString")) assertRoundTrips(expected, dataClass) } 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 a320470cf23..5bc6e768ed8 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 @@ -89,7 +89,8 @@ data class DataClassWithNestedParameterizedDataClass( data class DataClassWithNestedParameterized( val parameterizedDataClass: DataClassParameterized, - val other: B + val other: B, + val optionalOther: B? ) data class DataClassWithPair(val pair: Pair) diff --git a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt index 30fc6f7fbb4..ed9e1bfb43a 100644 --- a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt +++ b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt @@ -373,7 +373,7 @@ class KotlinSerializerCodecTest { |"nestedParameterized": { | "parameterizedDataClass": | {"number": 4.2, "string": "myString", "parameterizedList": [{"name": "embedded1"}]}, - | "other": "myOtherString" + | "other": "myOtherString", "optionalOther": "myOptionalOtherString" | } |}""" .trimMargin() @@ -381,7 +381,9 @@ class KotlinSerializerCodecTest { DataClassWithNestedParameterizedDataClass( "myId", DataClassWithNestedParameterized( - DataClassParameterized(4.2, "myString", listOf(DataClassEmbedded("embedded1"))), "myOtherString")) + DataClassParameterized(4.2, "myString", listOf(DataClassEmbedded("embedded1"))), + "myOtherString", + "myOptionalOtherString")) assertRoundTrips(expected, dataClass) } diff --git a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt index a58ae541d03..2511c7b0418 100644 --- a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt +++ b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt @@ -120,7 +120,8 @@ data class DataClassWithNestedParameterizedDataClass( @Serializable data class DataClassWithNestedParameterized( val parameterizedDataClass: DataClassParameterized, - val other: B + val other: B, + val optionalOther: B? ) @Serializable data class DataClassWithPair(val pair: Pair)