Menu Docs
Página inicial do Docs
/ / /
Kotlin Coroutine
/ /

Serialização Kotlin

Nesta página

  • Visão geral
  • Tipos suportados
  • Adicionar serialização de Kotlin ao seu projeto
  • Anotar classes de dados
  • Exemplo de serializador personalizado
  • Personalizar a Configuração do Serializador
  • Exemplo de codec personalizado
  • Serialização polimórfica
  • Exemplo de classes de dados polimórficos
  • Serialize datas e horários
  • Biblioteca kotlinx-datetime
  • Classe de dados de exemplo com datas e horários

O driver do Kotlin suporta a biblioteca kotlinx.serialization para serializar e desserializar objetos do Kotlin.

O driver fornece um serializador Bson eficiente que você pode usar com classes marcadas como @Serializable para lidar com a serialização de objetos Kotlin em dados BSON.

Você também pode instalar a biblioteca do bson-kotlinx para suportar códigos personalizados com configurações para codificar padrões, codificar nulos e definir discriminadores de classe.

Observação

Para saber como usar a interface Codec em vez da biblioteca de serialização Kotlin para especificar a codificação e a decodificação personalizadas de objetos Kotlin para dados BSON, consulte o guiaCodecs .

Você pode escolher a serialização do Kotlin se já estiver familiarizado com a estrutura ou se preferir usar uma abordagem idiomática do Kotlin.

Embora você possa usar o driver Kotlin com a biblioteca de Json de serialização Kotlin, o serializador Json não oferece suporte direto a tipos de valor BSON, como ObjectId. Você deve fornecer um serializador personalizado que possa lidar com a conversão entre BSON e JSON.

O driver Kotlin suporta:

  • Todos os tipos de Kotlin suportados pela biblioteca de serialização de Kotlin

  • Todos os tipos de BSONdisponíveis

O suporte à serialização no driver do Kotlin depende da biblioteca oficial de serialização do Kotlin.

Selecione uma das abas abaixo para ver como adicionar as dependências de serialização ao seu projeto usando os gerenciadores de pacotes Gradle e Maven:

Se você estiver usando o Gradle para gerenciar suas dependências, adicione o seguinte à sua build.gradle.kts lista de dependências do :

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

Se você estiver usando o Maven para gerenciar suas dependências, adicione o seguinte à sua pom.xml lista de dependências do :

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

Para declarar uma classe como serializável, anote suas classes de dados do Kotlin com a anotação @Serializable da estrutura de serialização do Kotlin.

Você pode utilizar suas classes de dados em seu código normalmente após marcá-las como serializáveis. O driver do Kotlin e a estrutura de serialização do Kotlin gereciam a serialização e desserialização do BSON.

Este exemplo mostra uma classe de dados simples anotada com o seguinte:

  • @Serializable para marcar a classe como serializável.

  • @SerialName para especificar o nome das propriedades id e manufacturer no documento BSON. Pode ser usado no lugar das anotações do @BsonId e @BsonProperty, que não são compatíveis com classes serializáveis.

  • @Contextual para marcar a propriedade BSON id para utilizar o ObjectIdSerializer embutido. Esta anotação é necessária para que os tipos BSON sejam serializados corretamente.

@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
)

Observação

Você não pode utilizar anotações do pacote org.bson.codecs.pojo.annotations em classes de dados do @Serializable.

Para mais informações sobre classes serializáveis e classes de anotação disponíveis, consulte a documentação Serialização oficial de Kotlin.

Você pode criar um serializador personalizado para gerenciar como seus dados são representados em BSON. O driver do Kotlin usa a interface do KSerializer do pacote kotlinx.serialization para implementar serializadores personalizados. Você pode especificar o serializador personalizado como o parâmetro para a anotação @Serializable para um campo específico.

O exemplo abaixo mostra como criar uma instância personalizada do KSerializer para converter um kotlinx.datetime.Instant para um 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}")
}
}
}

O código abaixo mostra a classe de dados PaintOrder na qual o campo orderDate tem uma anotação que especifica a classe de serializador personalizado definida no código anterior:

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

Para obter mais informações sobre os métodos e as classes mencionadas nesta seção, consulte a seguinte documentação da API:

Você pode utilizar a classe KotlinSerializerCodec do pacote org.bson.codecs.kotlinx para criar um codec para suas classes de dados do @Serializable e personalizar o que é armazenado.

Use a classe BsonConfiguration para definir a configuração, incluindo se deseja codificar padrões, codificar nulos ou definir discriminadores de classe.

Para criar um codec personalizado, instale a dependência do bson-kotlinx no seu projeto. Selecione uma das abas abaixo para ver como adicionar a dependência ao seu projeto usando os gerenciadores de pacotes Gradle e Maven:

Se você estiver usando o Gradle para gerenciar suas dependências, adicione o seguinte à sua build.gradle.kts lista de dependências do :

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

Se você estiver usando o Maven para gerenciar suas dependências, adicione o seguinte à sua pom.xml lista de dependências do :

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

Observação

bson-kotlin Dependency

Você também pode opcionalmente instalar a dependência do bson-kotlin através do registro de codec padrão. Essa dependência usa a reflexão e o registro do codec para oferecer suporte a classes de dados Kotlin, mas não oferece suporte a determinadas anotações POJO, como BsonDiscriminator, BsonExtraElementse BsonConstructor. Para saber mais, consulte a documentação da API bson-kotlin.

Geralmente, recomendamos que instale e utilize a biblioteca bson-kotlinx mais rápida para configuração de codec.

Em seguida, você pode definir seu codec usando o método KotlinSerializerCodec.create() e adicioná-lo ao registro.

O exemplo seguinte mostra como criar um codec utilizando o método KotlinSerializerCodec.create() e configurá-lo para não codificar padrões:

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
)

Para obter mais informações sobre os métodos e as classes mencionadas nesta seção, consulte a seguinte documentação da API:

O driver Kotlin suporta nativamente serialização e desserialização de classes polimórficas. Quando você marca uma interface selada e classes de dados que herdam essa interface com a anotação @Serializable , o driver usa uma implementação KSerializer para lidar com a conversão de seus tipos de e para BSON.

Quando você insere uma instância de uma classe de dados polimórficos no MongoDB, o driver adiciona o campo _t, o campo discriminador. O valor deste campo é o nome da classe de dados.

O exemplo seguinte cria uma interface e duas classes de dados que herdam esta interface. Nas classes de dados, o campo id é marcado com as anotações descritas na seção Anotar Classes de Dados :

@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

Em seguida, você pode executar operações com classes de dados como de costume. O exemplo a seguir parametriza a coleção com a interface Person e, em seguida, executa operações com as classes polimórficas Teacher e Student. Ao recuperar documentos, o driver detecta automaticamente o tipo com base no valor do discriminador e os desserializa adequadamente.

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}}

Nesta seção, você pode aprender sobre como usar a serialização do Kotlin para trabalhar com tipos de data e hora.

kotlinx-datetime é uma biblioteca Kotlin que oferece um alto nível de controle sobre como seus valores de data e hora são serializados. Para utilizar a biblioteca, adicione a dependência kotlinx-datetime à lista de dependência do seu projeto.

Selecione a partir das seguintes guias para ver como adicionar a dependência do kotlinx-datetime ao seu projeto utilizando os gerenciadores de pacote Gradle e 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 saber mais sobre esta biblioteca, consulte o repositório kotlinx-datetime no Github.

Após adicionar a dependência da biblioteca, você pode implementar serializadores da biblioteca do kotlinx-datetime que mapeiam seus valores de campo de classe de dados para os tipos esperados no BSON.

Neste exemplo, o driver serializa os campos da classe de dados Appointment com o seguinte comportamento:

  • name: o driver serializa o valor como uma string.

  • date: o driver utiliza o serializador kotlinx-datetime porque o campo tem a anotação @Contextual . LocalDate valores são serializados como datas BSON.

  • time: o driver serializa o valor como uma string porque ele não tem a anotação @Contextual . Este é o comportamento de serialização padrão para valores LocalTime .

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

O exemplo seguinte insere uma instância da classe de dados Appointment na coleção appointments :

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

No MongoDB, o valor LocalDate é armazenado como uma data BSON e o campo time é armazenado como uma string por serialização padrão:

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

Voltar

Documentos