Para agentes de IA: um índice de documentação está disponível em https://www.mongodb.com/pt-br/docs/llms.txt — as versões de markdown de todas as páginas estão disponíveis anexando .md a qualquer caminho de URL.
Menu Docs

Codificar dados com codecs de tipo

Neste guia, você pode aprender sobre codecs e as classes de suporte que lidam com a codificação e decodificação de objetos Scala de e para dados BSON no driver Scala. A abstração do Codec permite mapear qualquer tipo Scala para um tipo BSON correspondente. Use isso para mapear seus objetos de domínio diretamente de e para o BSON, em vez de usar um objeto intermediário baseado em mapa, como Document ou BsonDocument.

A interface do Codec contém métodos abstratos para codificar e decodificar objetos Scala de e para dados BSON. Implemente esses métodos para definir a lógica de conversão entre BSON e o tipo Scala da sua implementação Codec.

To implement the Codec interface, define the interface's encode(), decode(), and getEncoderClass() methods. To see a code example that implements these methods, see the Basic Custom Codec Example section.

O método encode() codifica uma instância do tipo Scala para BSON para que o driver possa armazená-la no MongoDB. Este método requer os seguintes parâmetros:

Parameter Type
Descrição

writer

Uma instância de uma classe que implementa o BsonWriter, uma interface que expõe métodos para escrever um documento BSON. Use esta instância para gravar seu valor BSON usando o método de gravação apropriado para seu tipo de valor BSON.

value

Os dados que o método codifica. O tipo value deve corresponder ao parâmetro de tipo que você atribuiu à sua implementação Codec.

encoderContext

Metadados sobre o objeto Scala que o método codifica para BSON, incluindo se deve armazenar o valor atual em uma coleção MongoDB.

O método encode() não retorna um valor.

O método decode() usa os dados BSON para decodificar uma instância do tipo Scala. Este método requer os seguintes parâmetros:

Parameter Type
Descrição

bsonReader

Uma instância de uma classe que implementa BsonReader, uma interface que expõe métodos para ler um documento BSON.

decoderContext

Metadados sobre os dados BSON que o método decodifica para um objeto Scala.

O método getEncoderClass() retorna uma instância do tipo Scala definido no Codec. Este método fornece as informações de tipo que a Java Virtual Machine (JVM) apaga em tempo de execução.

As amostras de código a seguir usam a característica selada PowerStatus e a classe PowerStatusCodec para mostrar como você pode implementar um Codec personalizado.

A característica selada PowerStatus usa os objetos de caso On e Off para representar os estados de um interruptor elétrico:

sealed trait PowerStatus
object PowerStatus {
case object On extends PowerStatus
case object Off extends PowerStatus
}

A classe PowerStatusCodec implementa a interface Codec para codificar valores PowerStatus em valores booleanos BSON correspondentes. O método encode() codifica um valor PowerStatus para um valor booleano BSON e o método decode() decodifica um valor booleano BSON para um valor PowerStatus.

class PowerStatusCodec extends Codec[PowerStatus] {
override def encode(writer: BsonWriter, value: PowerStatus,
encoderContext: EncoderContext): Unit = {
if (value != null) {
writer.writeBoolean(value == PowerStatus.On)
}
}
override def decode(reader: BsonReader,
decoderContext: DecoderContext): PowerStatus = {
if (reader.readBoolean()) PowerStatus.On else PowerStatus.Off
}
override def getEncoderClass: Class[PowerStatus] = classOf[PowerStatus]
}

To use the PowerStatusCodec class, you must add an instance of the class to your CodecRegistry interface, which maps your Codec to the corresponding Scala type. The driver can encode and decode a type only if the CodecRegistry contains a Codec for that type. To learn how to include your custom Codec in your CodecRegistry interface, see the CodecRegistry section of this page.

Para obter mais informações sobre as classes e interfaces nesta seção, consulte a seguinte Documentação da API:

Um CodecRegistry é uma coleção imutável de instância Codec. Para criar uma instância CodecRegistry, use um dos seguintes métodos de fábrica estática da classe CodecRegistries. Cada método cria o registro a partir de uma fonte diferente de instância Codec:

Método
Descrição

fromCodecs()

Cria um registro a partir das instâncias Codec que você passa para o método

fromProviders()

Cria um registro a partir das instâncias Codec que as instâncias CodecProvider que você passa para o método fornecem

fromRegistries()

Cria um registro combinando as outras CodecRegistry instâncias que você passa para o método

Os exemplos a seguir usam duas implementações Codec:

  • IntegerCodec: Um Codec no pacote BSON que codifica valores Java Integer para valores inteiros BSON 32-bit.

  • PowerStatusCodec: A sample Codec that decodes PowerStatus values to BSON Booleans.

O exemplo a seguir mostra como construir uma instância CodecRegistry usando o método fromCodecs() para atribuir essas implementações ao registro:

val codecRegistry = CodecRegistries.fromCodecs(
new IntegerCodec(), new PowerStatusCodec()
)

O exemplo a seguir recupera as instâncias Codec no exemplo anterior da coleção CodecRegistry:

val powerStatusCodec: Codec[PowerStatus] =
codecRegistry.get(classOf[PowerStatus])
val integerCodec: Codec[Integer] =
codecRegistry.get(classOf[Integer])

Observação

Se você chamar o método get() em uma instância Codec para uma classe não registrada, o driver lançará um CodecConfigurationException.

The default codec registry is a set of CodecProvider classes that encode between commonly used Scala and MongoDB types. The driver automatically uses the default codec registry unless you specify a custom codec registry. To learn more about the CodecProvider interface, see the CodecProvider section.

Se for necessário substituir o comportamento de uma ou mais classes Codec, mas manter o comportamento do registro de codecs padrão para as outras classes, você poderá especificar todos os registros em ordem de precedência. Por exemplo, para substituir o comportamento do provedor padrão de um Codec para um tipo personalizado com seu MyEnumCodec, adicione-o à lista de registros antes do registro de codecs padrão. O exemplo a seguir mostra esse padrão:

val newRegistry = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(new MyEnumCodec()),
MongoClientSettings.getDefaultCodecRegistry()
)

Para obter mais informações sobre as classes e interfaces nesta seção, consulte a seguinte Documentação da API:

A interface CodecProvider contém métodos abstratos que criam instâncias do Codec e as atribuem a uma instância do CodecRegistry. Assim como a interface CodecRegistry, a interface CodecProvider define um método get() que retorna instâncias do Codec. A biblioteca BSON utiliza essas instâncias do Codec para codificar entre Scala e tipos de dados BSON.

Utilize um CodecProvider ao adicionar uma classe ao seu código cujos campos precisam de objetos Codec correspondentes. Quando cada campo requer sua própria instância Codec, você deve instanciar os objetos Codec para cada campo antes de instanciar a instância Codec para a classe. Utilize o parâmetro CodecRegistry no método get() para passar qualquer uma das instâncias Codec em que o Codec confia em um construtor.

O exemplo a seguir mostra como implementar uma interface CodecProvider. O driver usa a interface MonolightCodecProvider implementada para criar uma instância MonolightCodec para a classe Monolight.

class MonolightCodecProvider extends CodecProvider {
override def get[T](clazz: Class[T], registry: CodecRegistry): Codec[T] = {
if (clazz == classOf[Monolight]) {
new MonolightCodec(registry).asInstanceOf[Codec[T]]
} else {
null
}
}
}

For a complete implementation of a CodecProvider interface, including custom classes, see the Complete Custom Codec Example section of this guide.

Para obter mais informações sobre as classes e interfaces nesta seção, consulte a seguinte Documentação da API:

Nesta seção, você pode aprender a implementar as interfaces Codec e CodecProvider para definir a lógica de codificação e decodificação de uma classe Scala personalizada. Esta seção também mostra como especificar e usar suas implementações personalizadas para realizar operações de inserção e recuperação.

O trecho de código a seguir mostra a classe personalizada de exemplo Monolight e seus campos:

case class Monolight(
powerStatus: PowerStatus = PowerStatus.Off,
colorTemperature: Int = 0
)

A classe Monolight contém os seguintes campos, cada um dos quais requer uma implementação de interface Codec:

  • powerStatus describes if the light is switched on or off. The PowerStatusCodec class encodes PowerStatus values to BSON Booleans.

  • colorTemperature descreve a cor da luz e contém um valor Int. A classe IntegerCodec incluída na biblioteca BSON codifica valores colorTemperature para inteiros BSON de 32bits.

O seguinte exemplo de código mostra como implementar uma interface Codec para a classe Monolight. O construtor usa uma instância CodecRegistry para recuperar as instâncias Codec que ele precisa para codificar e decodificar os campos Monolight.

class MonolightCodec(registry: CodecRegistry) extends Codec[Monolight] {
private val powerStatusCodec: Codec[PowerStatus] =
registry.get(classOf[PowerStatus])
private val integerCodec: Codec[Integer] =
registry.get(classOf[Integer])
override def encode(writer: BsonWriter, value: Monolight,
encoderContext: EncoderContext): Unit = {
writer.writeStartDocument()
writer.writeName("powerStatus")
powerStatusCodec.encode(writer, value.powerStatus, encoderContext)
writer.writeName("colorTemperature")
integerCodec.encode(writer, value.colorTemperature, encoderContext)
writer.writeEndDocument()
}
override def decode(reader: BsonReader,
decoderContext: DecoderContext): Monolight = {
var powerStatus: PowerStatus = PowerStatus.Off
var colorTemperature: Int = 0
reader.readStartDocument()
while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
reader.readName() match {
case "powerStatus" =>
powerStatus = powerStatusCodec.decode(reader, decoderContext)
case "colorTemperature" =>
colorTemperature = integerCodec.decode(reader, decoderContext)
case "_id" =>
reader.readObjectId()
case _ =>
reader.skipValue()
}
}
reader.readEndDocument()
Monolight(powerStatus, colorTemperature)
}
override def getEncoderClass: Class[Monolight] = classOf[Monolight]
}

O exemplo de código a seguir mostra como construir instâncias Codec para os campos na classe Monolight e implementar um CodecProvider personalizado:

class MonolightCodecProvider extends CodecProvider {
override def get[T](clazz: Class[T], registry: CodecRegistry): Codec[T] = {
if (clazz == classOf[Monolight]) {
new MonolightCodec(registry).asInstanceOf[Codec[T]]
} else {
null
}
}
}

O método get() retorna um novo MonolightCodec quando o driver solicita um Codec para a classe Monolight. O método passa o CodecRegistry para o construtor MonolightCodec para que o MonolightCodec possa recuperar as instâncias Codec para seus campos, como PowerStatusCodec e IntegerCodec. Se o driver solicitar um Codec para qualquer outra classe, o método retornará null.

Após definir a lógica de conversão, você pode executar as seguintes operações:

  • Armazenar dados de instâncias da classe Monolight no MongoDB

  • Recuperar dados do MongoDB em instâncias da classe Monolight

O exemplo a seguir atribui a classe MonolightCodecProvider à instância MongoCollection passando-a para o método withCodecRegistry() . O exemplo insere uma nova instância Monolight na coleção chamando o método insertOne() e, em seguida, chamando o método find() para retornar a instância Monolight armazenada. A saída mostra a instância Monolight recuperada, o que confirma que os codecs personalizados codificaram e decodificaram os dados com sucesso.

object MonolightCodecExample {
def main(args: Array[String]): Unit = {
val uri = "<connection string URI>"
val mongoClient = MongoClient(uri)
val codecRegistry = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(
new IntegerCodec(), new PowerStatusCodec()
),
CodecRegistries.fromProviders(new MonolightCodecProvider()),
MongoClientSettings.getDefaultCodecRegistry()
)
val database = mongoClient.getDatabase("codecs_example_products")
val collection: MongoCollection[Monolight] = database
.getCollection[Monolight]("monolights")
.withCodecRegistry(codecRegistry)
val myMonolight = Monolight(PowerStatus.On, 5200)
Await.result(
collection.insertOne(myMonolight).toFuture(),
Duration.Inf
)
val lights = Await.result(
collection.find().toFuture(),
Duration.Inf
)
println(lights)
mongoClient.close()
}
}

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