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 Java de e para dados BSON no driver Java Reactive Streams. A Codec abstração do permite mapear qualquer tipo Java para um tipo BSON correspondente. Você pode usar essa abstração 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 BsonDocumentou.

Saiba como especificar a lógica de codificação e decodificação personalizada usando a abstração Codec nas seguintes seções:

Para saber mais sobre como personalizar a lógica de codificação e decodificação para objetos Java antigos e simples (POJOs), consulte o guia Usar POJOs para modelar seus dados.

A interface do Codec contém métodos abstratos para serializar e desserializar objetos Java para dados BSON. Defina sua lógica de conversão entre BSON e seu objeto Java em sua implementação desta interface.

Para implementar a interface do Codec, substitua os métodos abstratos encode(), decode() e getEncoderClass().

O método encode() exige os seguintes parâmetros:

Parameter Type
Descrição

writer

Uma instância de uma classe que implementa o BsonWriter, um tipo de interface que expõe métodos para escrever um documento BSON. Por exemplo, a implementação do BsonBinaryWriter grava em um fluxo binário de dados. Use esta instância para escrever seu valor BSON usando o método de escrita apropriado.

value

Os dados que sua implementação codifica. O tipo deve corresponder à variável de tipo atribuída à sua implementação.

encoderContext

Contém metadados sobre os dados de objeto Java que codifica para BSON, incluindo se deve armazenar o valor atual em uma coleção MongoDB .

Este método utiliza a instância BsonWriter para enviar o valor codificado para o MongoDB e não retorna um valor.

O método decode() retorna sua instância de objeto Java preenchida com o valor dos dados BSON. Este método requer os seguintes parâmetros:

Parameter Type
Descrição

bsonReader

Uma instância de uma classe que implementa o BsonReader, um tipo de interface que expõe métodos para ler um documento BSON. Por exemplo, a implementação do BsonBinaryReader lê a partir de um fluxo binário de dados.

decoderContext

Contém informações sobre os dados BSON que decodifica para um objeto Java.

O método getEncoderClass() retorna uma classe classe Java Java não pode inferir o tipo devido ao apagamento do tipo.

Os seguintes exemplos de código mostram como implementar um Codec personalizado.

O enumeração ReadStatus contém os valores READ e UNREAD para representar se um livro foi lido.

public enum ReadStatus {
READ,
UNREAD
}

A classe ReadStatusCodec implementa Codec para converter os valores Java enum em valores booleanos BSON correspondentes. O método encode() converte um ReadStatus em um booleano BSON e o método decode() executa a conversão na direção oposta.

public class ReadStatusCodec implements Codec<ReadStatus> {
@Override
public void encode(BsonWriter writer, ReadStatus value, EncoderContext encoderContext) {
writer.writeBoolean(value.equals(ReadStatus.READ) ? Boolean.TRUE : Boolean.FALSE);
}
@Override
public ReadStatus decode(BsonReader reader, DecoderContext decoderContext) {
return reader.readBoolean() ? ReadStatus.READ : ReadStatus.UNREAD;
}
@Override
public Class<ReadStatus> getEncoderClass() {
return ReadStatus.class;
}
}

Você pode adicionar uma instância do no ReadStatusCodec CodecRegistryseu, que contém um mapeamento entre seu Codec e o tipo de objeto Java ao qual ele se aplica. Continue para a seção CodecRegistry desta página para ver como incluir Codec seu.

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

CodecRegistry Um coleção é uma coleção imutável de Codec instâncias que codificam e decodificam as classes Java especificadas. Você pode usar qualquer um dos seguintes métodos de fábrica estática de classe CodecRegistries para construir uma CodecRegistry a partir das instâncias Codec contidas nos tipos associados:

  • fromCodecs()

  • fromProviders()

  • fromRegistries()

O seguinte trecho de código mostra como construir um CodecRegistry utilizando o método fromCodecs():

CodecRegistry codecRegistry = CodecRegistries.fromCodecs(new IntegerCodec(), new ReadStatusCodec());

No exemplo anterior , o CodecRegistry inclui as seguintes implementações do Codec:

  • IntegerCodec, um Codec que converte Integers e faz parte do pacote BSON.

  • ReadStatusCodec, nossa amostra Codec que converte valores de enumeração Java em booleanos BSON.

Você pode recuperar as instâncias Codec da instância CodecRegistry no exemplo anterior usando o código a seguir:

Codec<ReadStatus> readStatusCodec = codecRegistry.get(ReadStatus.class);
Codec<Integer> integerCodec = codecRegistry.get(Integer.class);

Se você tentar recuperar uma instância do Codec para uma classe que não está registrada, o método do get() lançará um CodecConfigurationException.

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

Um CodecProvider é uma interface que contém métodos abstratos que criam instâncias do Codec e atribuem a uma instância do CodecRegistry. Semelhante ao CodecRegistry, a biblioteca BSON utiliza as instâncias do Codec recuperadas pelo método get() para converter entre Java e tipos de dados BSON.

No entanto, se você adicionar uma classe que contém campos que exigem Codec objetos correspondentes, você deverá instanciar os objetos Codec para os campos de classe antes de instanciar o Codec para a classe. Você pode utilizar o parâmetro CodecRegistry no método get() para passar quaisquer instâncias do Codec em que o Codec confia.

O exemplo de código a seguir mostra como implementar CodecProvider para passar ao BookCodec quaisquer instâncias Codec necessárias em uma instância CodecRegistry, como o ReadStatusCodec do exemplo anterior:

public class BookCodecProvider implements CodecProvider {
public BookCodecProvider() {}
@Override
@SuppressWarnings("unchecked")
public <T> Codec<T> get(Class<T> clazz, CodecRegistry registry) {
if (clazz == Book.class) {
return (Codec<T>) new BookCodec(registry);
}
// return null when not a provider for the requested class
return null;
}
}

Para visualizar um exemplo executável que demonstra operações de leitura e escrita usando essas Codec classes, consulte a seção Exemplo de codec personalizado deste guia.

Ao trabalhar com POJOs, considere utilizar o PojoCodecProvider para minimizar o código duplicado ao converter tipos de dados comumente utilizados e personalizar seu comportamento. Consulte nosso guia Use POJOs to Model Your Data para obter mais informações.

O registro de codec padrão é um definir de classes CodecProvider que especificam a conversão entre tipos Java e MongoDB comumente usados. O driver usa automaticamente o registro de codec padrão, a menos que você especifique um registro diferente.

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 tipos de enumeração pelo seu MyEnumCodec personalizado, adicione-o à lista de registros antes do registro de codecs padrão, conforme mostrado no exemplo a seguir:

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

Para obter mais informações sobre as classes e interfaces nesta seção, consulte as seguintes seções de documentação da API:

A classe BsonTypeClassMap contém um mapeamento recomendado entre os tipos BSON e Java . Você pode usar essa classe em seu Codec ou CodecProvider personalizado para ajudar a gerenciar quais tipos Java decodificam seus tipos BSON para classes de contêiner que implementam Iterable ou Map, como a classe Document.

Você pode adicionar ou modificar o mapeamento padrão do BsonTypeClassMap passando um Map que contenha entradas novas ou de substituição.

O seguinte trecho de código mostra como recuperar o tipo de classe Java que corresponde ao tipo BSON na instância BsonTypeClassMap padrão:

BsonTypeClassMap bsonTypeClassMap = new BsonTypeClassMap();
Class<?> clazz = bsonTypeClassMap.get(BsonType.ARRAY);
System.out.println("Java type: " + clazz.getName());

Esse código gera o seguinte:

Java type: java.util.List

Você pode modificar esses mapeamentos na sua instância especificando substituições no construtor BsonTypeClassMap. O exemplo a seguir mostra como substituir o mapeamento de ARRAY em sua instância BsonTypeClassMap pela classe Set :

Map<BsonType, Class<?>> replacements = new HashMap<BsonType, Class<?>>();
replacements.put(BsonType.ARRAY, Set.class);
BsonTypeClassMap bsonTypeClassMap = new BsonTypeClassMap(replacements);
Class<?> clazz = bsonTypeClassMap.get(BsonType.ARRAY);
System.out.println("Java type: " + clazz.getName());

Esse código gera o seguinte:

Java type: java.util.Set

Para obter uma lista completa dos mapeamentos padrão, consulte a documentação da API BsonTypeClassMap.

Dica

Para obter exemplos de como a Document classe usa,BsonTypeClassMap consulte o código-fonte do driver para as classes DocumentCodecProvider e DocumentCodec.

Esta seção mostra como implementar Codec e CodecProvider para definir a lógica de codificação e decodificação de uma classe Java personalizada. Ele também mostra como especificar e usar suas implementações personalizadas para realizar operações de inserção e recuperação.

O exemplo a seguir define uma classe personalizada chamada Book e seus campos para armazenamento e recuperação em uma coleção MongoDB :

public class Book {
private String title;
private ReadStatus readStatus = ReadStatus.UNREAD;
private Integer pageCount;
public Book() {}
// ...

Esta classe contém os seguintes campos, cada um dos quais requer um Codec:

  • title contém um valor String para o qual o exemplo utiliza o StringCodec incluído na biblioteca BSON.

  • readStatus descreve se um livro foi lido, para o qual o exemplo usa o ReadStatusCodec personalizado que converte valores de enumeração em booleanos BSON.

  • pageCount contém um valor Integer para o qual o exemplo utiliza o IntegerCodec incluído na biblioteca BSON.

O seguinte exemplo de código mostra como implementar um Codec para a classe Book . Observe que o construtor espera uma instância de CodecRegistry da qual ele recupera as instâncias de Codec necessárias para codificar e decodificar seus campos:

public class BookCodec implements Codec<Book> {
private Codec<String> stringCodec;
private Codec<ReadStatus> readStatusCodec;
private Codec<Integer> integerCodec;
public BookCodec(CodecRegistry registry) {
this.stringCodec = registry.get(String.class);
this.readStatusCodec = registry.get(ReadStatus.class);
this.integerCodec = registry.get(Integer.class);
}
// Defines an encode() method to convert Book field values to BSON values
@Override
public void encode(BsonWriter writer, Book value, EncoderContext encoderContext) {
writer.writeStartDocument();
writer.writeName("title");
stringCodec.encode(writer, value.getTitle(), encoderContext);
writer.writeName("readStatus");
readStatusCodec.encode(writer, value.getReadStatus(), encoderContext);
writer.writeName("pageCount");
integerCodec.encode(writer, value.getPageCount(), encoderContext);
writer.writeEndDocument();
}
// Defines a decode() method to convert BSON values to Book field values
@Override
public Book decode(BsonReader reader, DecoderContext decoderContext) {
Book book = new Book();
reader.readStartDocument();
while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
String fieldName = reader.readName();
if (fieldName.equals("title")) {
book.setTitle(stringCodec.decode(reader, decoderContext));
} else if (fieldName.equals("readStatus")) {
book.setReadStatus(readStatusCodec.decode(reader, decoderContext));
} else if (fieldName.equals("pageCount")) {
book.setPageCount(integerCodec.decode(reader, decoderContext));
} else if (fieldName.equals("_id")) {
reader.readObjectId();
} else {
reader.skipValue();
}
}
reader.readEndDocument();
return book;
}
// Returns an instance of the Book class, since Java cannot infer the class type
@Override
public Class<Book> getEncoderClass() {
return Book.class;
}
}

Para disponibilizar as instâncias Codec dos campos para Book, implemente um CodecProvider personalizado mostrado no exemplo de código a seguir :

public class BookCodecProvider implements CodecProvider {
public BookCodecProvider() {}
@Override
@SuppressWarnings("unchecked")
public <T> Codec<T> get(Class<T> clazz, CodecRegistry registry) {
if (clazz == Book.class) {
return (Codec<T>) new BookCodec(registry);
}
// return null when not a provider for the requested class
return null;
}
}

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

  • Armazenar dados de instâncias de Book no MongoDB

  • Recuperar dados do MongoDB em instâncias de Book

A classe de exemplo a seguir contém código que atribui o BookCodecProvider à instância MongoCollection passando-o para o método withCodecRegistry() . A classe de exemplo também insere e recupera dados utilizando a classe Book e codecs associados:

public class BookCodecExample {
public static void main(String[] args) {
String uri = "<MongoDB connection URI>";
try (MongoClient mongoClient = MongoClients.create(uri)) {
CodecRegistry codecRegistry = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(new ReadStatusCodec()),
CodecRegistries.fromProviders(new BookCodecProvider()),
MongoClientSettings.getDefaultCodecRegistry());
MongoDatabase database = mongoClient.getDatabase("codecs_example_db");
MongoCollection<Book> collection = database.getCollection("books", Book.class)
.withCodecRegistry(codecRegistry);
// construct and insert an instance of Book
Book myBook = new Book();
myBook.setTitle("The Hobbit");
myBook.setReadStatus(ReadStatus.READ);
myBook.setPageCount(310);
Mono.from(collection.insertOne(myBook)).block();
// retrieve one or more instances of Book
Flux.from(collection.find())
.doOnNext(System.out::println)
.blockLast();
}
}
}

Se você executar o exemplo anterior, a saída será semelhante ao seguinte:

Book [title=The Hobbit, readStatus=READ, pageCount=310]

Para obter mais informações sobre os métodos e classes mencionados neste guia, consulte a seguinte documentação da API: