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.

Para implementar a Codec interface, defina os encode() métodos, decode() e da getEncoderClass() interface. Para ver um exemplo de código que implementa esses métodos, consulte a seção Exemplo básico de codec personalizado .

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

Para usar a PowerStatusCodec classe , você deve adicionar uma instância da classe à sua CodecRegistry interface, que mapeia seu Codec para o tipo Scala correspondente. O driver pode codificar e decodificar um tipo somente se o CodecRegistry contiver um Codec para esse tipo. Para saber como incluir seu personalizado Codec em sua CodecRegistry interface do, consulte a seção CodecRegistry desta página.

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: uma amostra Codec que decodifica PowerStatus valores para booleanos BSON.

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.

O registro de codec padrão é um definir de CodecProvider classes que codificam entre tipos Scala e MongoDB comumente usados. O driver usa automaticamente o registro de codec padrão, a menos que você especifique um registro de codec personalizado. Para saber mais sobre a CodecProvider interface do, consulte a seção CodecProvider.

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

Para obter uma implementação completa de uma CodecProvider interface, incluindo classes personalizadas, consulte a seção Exemplo completo de codec personalizado deste guia.

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 descreve se a luz está ligada ou apagada. A classe PowerStatusCodec codifica PowerStatus valores para booleanos BSON.

  • 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()
}
}
List(Monolight(On,5200))

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