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
Visão geral
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.
Tipos suportados
O driver Kotlin suporta:
Todos os tipos de Kotlin suportados pela biblioteca de serialização de Kotlin
Todos os tipos de BSONdisponíveis
Adicionar serialização de Kotlin ao seu projeto
Support for serialização in the Kotlin driver depends on the official Kotlin serialização library.
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 :
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.5.1") implementation("org.mongodb:bson-kotlinx:5.2.1")
Se você estiver usando o Maven para gerenciar suas dependências, adicione o seguinte à sua pom.xml
lista de dependências do :
<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.1</version> </dependency>
Anotar classes de dados
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 propriedadesid
emanufacturer
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 BSONid
para utilizar oObjectIdSerializer
embutido. Esta anotação é necessária para que os tipos BSON sejam serializados corretamente.
data class PaintOrder( // Use instead of @BsonId val id: ObjectId?, val color: String, val qty: Int, 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.
Exemplo de serializador personalizado
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:
data class PaintOrder( val color: String, val qty: Int, 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:
Personalizar a Configuração do Serializador
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 :
implementation("org.mongodb:bson-kotlinx:5.2.1")
Se você estiver usando o Maven para gerenciar suas dependências, adicione o seguinte à sua pom.xml
lista de dependências do :
<dependency> <groupId>org.jetbrains.kotlinx</groupId> <artifactId>bson-kotlinx</artifactId> <version>5.2.1</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
, BsonExtraElements
e 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.
Exemplo de codec personalizado
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:
Serialização polimórfica
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.
Exemplo de classes de dados polimórficos
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 :
sealed interface Person { val name: String } data class Student( val id: ObjectId, override val name: String, val grade: Int, ) : Person data class Teacher( 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}}
Serialize datas e horários
Nesta seção, você pode aprender sobre como usar a serialização do Kotlin para trabalhar com tipos de data e hora.
Biblioteca kotlinx-datetime
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 :
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1")
<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.
Classe de dados de exemplo com datas e horários
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 serializadorkotlinx-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 valoresLocalTime
.
data class Appointment( val name: String, 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", }