Visão geral
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.
Interface do Codec
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 .
Método de codificação()
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 |
|---|---|
| Uma instância de uma classe que implementa o |
| Os dados que o método codifica. O tipo |
| 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.
Método decode()
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 |
|---|---|
| Uma instância de uma classe que implementa |
| Metadados sobre os dados BSON que o método decodifica para um objeto Scala. |
método getEncoderClass()
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.
Exemplo de codec personalizado básico
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:
CodecRegistry Coleção
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 |
|---|---|
| Cria um registro a partir das instâncias |
| Cria um registro a partir das instâncias |
| Cria um registro combinando as outras |
Os exemplos a seguir usam duas implementações Codec:
IntegerCodec: UmCodecno pacote BSON que codifica valores JavaIntegerpara valores inteiros BSON 32-bit.PowerStatusCodec: uma amostra
Codecque decodificaPowerStatusvalores 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.
Registro Codec padrão
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:
Interface CodecProvider
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:
Exemplo completo de codec personalizado
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:
powerStatusdescreve se a luz está ligada ou apagada. A classe PowerStatusCodec codificaPowerStatusvalores para booleanos BSON.colorTemperaturedescreve a cor da luz e contém um valorInt. A classeIntegerCodecincluída na biblioteca BSON codifica valorescolorTemperaturepara 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
Monolightno MongoDBRecuperar 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: