Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /

Serialización de Kotlin

El controlador Kotlin admite el kotlinx.serialization librería para serializar y deserializar objetos de Kotlin.

El driver proporciona un serializador Bson eficiente que puedes utilizar con clases marcadas como @Serializable para gestionar la serialización de objetos Kotlin en datos BSON.

También puedes instalar la librería bson-kotlinx para brindar soporte codecs personalizados con configuraciones para codificar valores por defecto, codificar valores nulos y definir discriminadores de clase.

Nota

Para aprender a usar la interfaz Codec en lugar de la librería de serialización de Kotlin para especificar la codificación y decodificación personalizada de objetos de Kotlin en datos BSON, consulte Codecs guía.

Puede optar por la serialización de Kotlin si ya está familiarizado con el framework o si prefiere utilizar un enfoque idiomático de Kotlin.

Aunque puedes usar el controlador de Kotlin con la librería de serialización de Kotlin Json, el serializador Json no admite directamente tipos de valores BSON como ObjectId. Debes proporcionar un serializador personalizado que pueda gestionar la conversión entre BSON y JSON.

El controlador de Kotlin admite:

  • Todos los tipos de Kotlin que son compatibles con la biblioteca de serialización de Kotlin

  • Todas las BSON typesdisponibles

El soporte para la serialización en el driver de Kotlin depende de la librería oficial de serialización de Kotlin.

Tip

Lista de Materiales

Recomendamos agregar el programa de materiales del driver JVM (BOM) a tu aplicación para gestionar las versiones de los artefactos del driver. Esto remueve la necesidad de especificar una versión para cualquier paquete individual cubierto por el BOM, lo que simplifica la gestión de dependencias. Para obtener más información, consulte el paso Agregar la factura de materiales del driver de la guía de inicio rápido.

Seleccione una de las siguientes pestañas para ver cómo agregar las dependencias de serialización a su proyecto mediante el uso de Gradle y Maven gestores de paquetes:

Si usas Gradle para gestionar tus dependencias, añade lo siguiente a tu lista de dependencias de build.gradle.kts:

build.gradle.kts
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.0")
implementation("org.mongodb:bson-kotlinx")

Si usas Maven para gestionar tus dependencias, añade lo siguiente a tu lista de dependencias pom.xml:

pom.xml
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-serialization-core</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>bson-kotlinx</artifactId>
</dependency>

Para declarar una clase como serializable, anota tus clases de datos de Kotlin con la anotación @Serializable del framework de serialización de Kotlin.

Puedes utilizar tus clases de datos en tu código de manera normal después de marcarlas como serializables. El driver de Kotlin y el marco de serialización de Kotlin gestionan la serialización y deserialización BSON.

Este ejemplo muestra una clase de datos simple anotada con lo siguiente:

  • @Serializable para marcar la clase como serializable.

  • @SerialName para especificar el nombre de las propiedades id y manufacturer en el documento BSON. Esto puede usarse en lugar de las anotaciones @BsonId y @BsonProperty, que no están soportadas en clases serializables.

  • @Contextual Para marcar la propiedad BSON id y usar la propiedad integrada ObjectIdSerializer. Esta anotación es necesaria para que los tipos BSON se serialicen correctamente.

@Serializable
data class PaintOrder(
@SerialName("_id") // Use instead of @BsonId
@Contextual val id: ObjectId?,
val color: String,
val qty: Int,
@SerialName("brand")
val manufacturer: String = "Acme" // Use instead of @BsonProperty
)

Nota

No puede utilizar anotaciones del paquete org.bson.codecs.pojo.annotations en las clases de datos de @Serializable.

Para obtener más información sobre las clases serializables y las clases de anotación disponibles,consulte la documentación oficial de serialización de Kotlin.

Puede consultar clases de datos anotadas mediante la clase Filtros del mongodb-driver-kotlin-extensions paquete. Esta clase permite crear filtros de consulta para nombres de campo anotados con la @SerialName anotación.

Tip

Para utilizar la Filters clase de la librería de extensión, debes añadir la dependencia mongodb-driver-kotlin-extensions a tu Proyecto. Para obtener más información, consulte la sección Añadir extensiones de Kotlin a su Proyecto de la guía Utilizar desarrolladores con clases de datos.

El siguiente ejemplo consulta la colección orders para los documentos que tienen un valor de campo brand de "Sherwin-Williams":

val queryFilter = eq(PaintOrder::manufacturer, "Sherwin-Williams")
val results = collection.find(queryFilter)

Puedes crear un serializador personalizado para gestionar la representación de tus datos en BSON. El controlador Kotlin utiliza la interfaz KSerializer del paquete kotlinx.serialization para implementar serializadores personalizados. Puedes especificar el serializador personalizado como parámetro de la anotación @Serializable para un campo específico.

El siguiente ejemplo muestra cómo crear una instancia personalizada de KSerializer para convertir un kotlin.time.Instant en un BsonDateTime:

object InstantAsBsonDateTime : KSerializer<Instant> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("InstantAsBsonDateTime", PrimitiveKind.LONG)
override fun serialize(encoder: Encoder, value: Instant) {
when (encoder) {
is BsonEncoder -> encoder.encodeBsonValue(BsonDateTime(value.toEpochMilliseconds()))
else -> throw SerializationException("Instant is not supported by ${encoder::class}")
}
}
override fun deserialize(decoder: Decoder): Instant {
return when (decoder) {
is BsonDecoder -> Instant.fromEpochMilliseconds(decoder.decodeBsonValue().asDateTime().value)
else -> throw SerializationException("Instant is not supported by ${decoder::class}")
}
}
}

El siguiente código muestra la clase de datos PaintOrder en la que el campo orderDate tiene una anotación que especifica la clase de serialización personalizada definida en el código anterior:

@Serializable
data class PaintOrder(
val color: String,
val qty: Int,
@Serializable(with = InstantAsBsonDateTime::class)
val orderDate: Instant,
)

Para obtener más información sobre los métodos y clases mencionados en esta sección, consulte la siguiente documentación de API:

Puedes utilizar la clase KotlinSerializerCodec del paquete org.bson.codecs.kotlinx para crear un codec para tus clases de datos @Serializable y personalizar lo que se almacena.

Use la clase BsonConfiguration para definir la configuración, incluyendo si se codifican los valores por defecto, los nulos, definir los discriminadores de clase o aplicar snake case.

Para crear un códec personalizado, instala la dependencia bson-kotlinx en tu proyecto. Seleccione de las siguientes pestañas para ver cómo añadir la dependencia a su proyecto utilizando los gestores de paquetes Gradle y Maven:

Si usas Gradle para gestionar tus dependencias, añade lo siguiente a tu lista de dependencias de build.gradle.kts:

build.gradle.kts
implementation("org.mongodb:bson-kotlinx")

Si usas Maven para gestionar tus dependencias, añade lo siguiente a tu lista de dependencias pom.xml:

pom.xml
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>bson-kotlinx</artifactId>
</dependency>

Nota

Dependencia bson-kotlin

También puedes instalar opcionalmente la dependencia bson-kotlin a través del registro de códecs por defecto. Esta dependencia utiliza la reflexión y el registro de códecs para admitir las clases de datos de Kotlin, pero no admite ciertas anotaciones POJO como BsonDiscriminator, BsonExtraElements y BsonConstructor. Para aprender más, consulte la documentación API de bson-kotlin.

En general, recomendamos que instale y utilice la biblioteca bson-kotlinx más rápida para la configuración del códec.

A continuación, puedes definir tu codec usando el KotlinSerializerCodec.create() método y añadirlo al registro.

El siguiente ejemplo muestra cómo crear un códec utilizando el método KotlinSerializerCodec.create() y configurarlo para no codificar valores predeterminados:

import org.bson.codecs.configuration.CodecRegistries
import org.bson.codecs.kotlinx.BsonConfiguration
import org.bson.codecs.kotlinx.KotlinSerializerCodec
val myCustomCodec = KotlinSerializerCodec.create<PaintOrder>(
bsonConfiguration = BsonConfiguration(encodeDefaults = false)
)
val registry = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(myCustomCodec), collection.codecRegistry
)

Al usar el paquete bson-kotlinx v5.4 o después, puedes dirigir al controlador para que serialice los nombres de los campos de clase de datos escritos en camel case a snake case en MongoDB. El siguiente ejemplo muestra cómo crear y registrar un códec personalizado para convertir los nombres de los campos de la clase de datos a snake case al establecer el parámetro bsonNamingStrategy en un códec:

import org.bson.codecs.kotlinx.BsonConfiguration
import org.bson.codecs.kotlinx.BsonNamingStrategy
val myCustomCodec = KotlinSerializerCodec.create<PaintOrder>(
bsonConfiguration = BsonConfiguration(bsonNamingStrategy = BsonNamingStrategy.SNAKE_CASE)
)
val registry = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(myCustomCodec), collection.codecRegistry
)

Para obtener más información sobre los métodos y clases mencionados en esta sección, consulte la siguiente documentación de API:

El controlador Kotlin admite de forma nativa la serialización y deserialización de clases polimórficas. Al marcar una interfaz sellada y las clases de datos que heredan dicha interfaz con la anotación @Serializable, el controlador utiliza una implementación KSerializer para gestionar la conversión de los tipos a y desde BSON.

Cuando insertas una instancia de una clase de datos polimórfica en MongoDB, o driver añade el campo _t, o campo discriminador. El valor de este campo es el nombre de la clase de datos.

El siguiente ejemplo crea una interfaz y dos clases de datos que heredan dicha interfaz. En las clases de datos, el id campo se marca con las anotaciones descritas en la sección "Anotar clases de datos":

@Serializable
sealed interface Person {
val name: String
}
@Serializable
data class Student(
@Contextual
@SerialName("_id")
val id: ObjectId,
override val name: String,
val grade: Int,
) : Person
@Serializable
data class Teacher(
@Contextual
@SerialName("_id")
val id: ObjectId,
override val name: String,
val department: String,
) : Person

A continuación, puede realizar operaciones con las clases de datos de la forma habitual. El siguiente ejemplo parametriza la colección con la interfaz Person y, a continuación, realiza operaciones con las clases polimórficas Teacher y Student. Al recuperar documentos, el controlador detecta automáticamente el tipo según el valor del discriminador y los deserializa en consecuencia.

val collection = database.getCollection<Person>("school")
val teacherDoc = Teacher(ObjectId(), "Vivian Lee", "History")
val studentDoc = Student(ObjectId(), "Kate Parker", 10)
collection.insertOne(teacherDoc)
collection.insertOne(studentDoc)
println("Retrieving by using data classes")
collection.withDocumentClass<Teacher>()
.find(Filters.exists("department"))
.first().also { println(it) }
collection.withDocumentClass<Student>()
.find(Filters.exists("grade"))
.first().also { println(it) }
println("\nRetrieving by using Person interface")
val resultsFlow = collection.withDocumentClass<Person>().find()
resultsFlow.collect { println(it) }
println("\nRetrieving as Document type")
val resultsDocFlow = collection.withDocumentClass<Document>().find()
resultsDocFlow.collect { println(it) }
Retrieving by using data classes
Teacher(id=..., name=Vivian Lee, department=History)
Student(id=..., name=Kate Parker, grade=10)
Retrieving by using Person interface
Teacher(id=..., name=Vivian Lee, department=History)
Student(id=..., name=Kate Parker, grade=10)
Retrieving as Document type
Document{{_id=..., _t=Teacher, name=Vivian Lee, department=History}}
Document{{_id=..., _t=Student, name=Kate Parker, grade=10}}

En esta sección, puede aprender a usar la serialización de Kotlin para trabajar con tipos de fecha y hora.

kotlinx-datetime es una librería de Kotlin que ofrece un alto nivel de control sobre cómo se serializan los valores de fecha y hora. Para usar la librería, agrega la dependencia kotlinx-datetime a la lista de dependencias de tu proyecto.

Seleccione de las siguientes pestañas para ver cómo agregar la dependencia kotlinx-datetime a su Proyecto utilizando los administradores de paquetes Gradle y Maven:

build.gradle.kts
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1")
pom.xml
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-datetime-jvm</artifactId>
<version>0.6.1</version>
</dependency>

Para obtener más información sobre esta librería, consulta el Repositorio kotlinx-datetime en GitHub.

Después de agregar la dependencia de la librería, puede implementar los serializadores de la librería kotlinx-datetime que asignan los valores de los campos de la clase de datos a los tipos esperados en BSON.

En este ejemplo, el driver serializa los campos de la clase de datos Appointment con el siguiente comportamiento:

  • name: El driver serializa el valor como una string.

  • date: El controlador utiliza el serializador kotlinx-datetime porque el campo tiene la anotación @Contextual. LocalDate valores se serializan como fechas BSON.

  • time: El driver serializa el valor como una string porque no tiene la anotación @Contextual. Este es el comportamiento de serialización por defecto para los valores LocalTime.

@Serializable
data class Appointment(
val name: String,
@Contextual val date: LocalDate,
val time: LocalTime,
)

El siguiente ejemplo inserta una instancia de la clase de datos Appointment en la colección appointments:

val collection = database.getCollection<Appointment>("appointments")
val apptDoc = Appointment(
"Daria Smith",
LocalDate(2024, 10, 15),
LocalTime(hour = 11, minute = 30)
)
collection.insertOne(apptDoc)

En MongoDB, el valor LocalDate se almacena como una fecha BSON y el campo time se almacena como una cadena mediante la serialización predeterminada:

{
"_id": ...,
"name": "Daria Smith",
"date": {
"$date": "2024-10-15T00:00:00.000Z"
},
"time": "11:30",
}

Volver

Documentos