AI エージェント向け: ドキュメントインデックスは https://www.mongodb.com/ja-jp/docs/llms.txt で利用できます。すべてのページの markdown バージョンは、いずれかの URL パスに .md を追加することで利用できます。
Docs Menu

タイプ コーデックによるデータのエンコード

このガイドでは、Java Reactive Streams ドライバーで Java オブジェクトと BSON データのエンコードとデコードを処理する Codec とサポート クラスについて学習できます。Codec 抽象化を使用して、対応する BSON 型に任意の Java 型をマッピングできます。また、DocumentBsonDocument のような中間マップベースのオブジェクトを使用せずに、ドメイン オブジェクトを BSON との間で直接マッピングするためにも使用できます。

次のセクションでは、Codec 抽象化を使用してカスタム エンコードおよびデコード ロジックを指定する方法を説明します。

POJO(Plain Old Java オブジェクト)のエンコードおよびデコードロジックのカスタマイズについて詳しくは、「POJO を使用したデータのモデル化」ガイドを参照してください。

Codec インターフェースには、Java オブジェクトを BSON データにシリアル化および逆シリアル化するための抽象メソッドが含まれています。このインターフェースの**実装**では、BSON と Java オブジェクト間の変換ロジックを定義できます。

Codec インターフェースを実装するには、encode()decode()、および getEncoderClass() 抽象メソッドをオーバーライドします。

encode() メソッドには次のパラメーターが必要です。

Parameter Type
説明

writer

BSON ドキュメントを書き込むためのメソッドを公開するインターフェース型である BsonWriter を実装するクラスのインスタンス。例えば、BsonBinaryWriter 実装はバイナリ ストリームのデータに書き込みます。このインスタンスを使用して、適切な書込みメソッドで BSON 値を書き込みます。

value

実装によってエンコードされるデータ。型は、実装に割り当てられた型変数と一致する必要があります。

encoderContext

現在の値を MongoDB コレクションに保存するかどうかなど、BSON にエンコードされる Java オブジェクト データに関するメタデータが含まれます。

このメソッドは、BsonWriter インスタンスを使用してエンコードされた値を MongoDB に送信し、値を返しません。

decode() メソッドは、BSON データから取得した値が設定された Java オブジェクト インスタンスを返します。このメソッドには次のパラメータが必要です。

Parameter Type
説明

bsonReader

BSON ドキュメントを読み取るためのメソッドを公開するインターフェース型である BsonReader を実装するクラスのインスタンス。たとえば、BsonBinaryReader 実装はバイナリ ストリームのデータから読み取ります。

decoderContext

Java オブジェクトにデコードされる BSON データに関する情報が含まれます。

Java は型消去により型を推論できないため、getEncoderClass() メソッドは Java クラスのクラス インスタンスを返します。

次のコード例は、カスタム Codec を実装する方法を示しています。

ReadStatus列挙型には、本が読まれたかどうかを表す値 READUNREAD が含まれています。

public enum ReadStatus {
READ,
UNREAD
}

ReadStatusCodec クラスは、Java enum 値を対応する BSON ブール値に変換するために Codec を実装します。encode() メソッドは ReadStatus を BSON ブール値に変換し、decode() メソッドは逆方向の変換を実行します。

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

Codec とそれが適用される Java Realm オブジェクトタイプとの間のマッピングを含む ReadStatusCodec のインスタンスを CodecRegistry に追加できます。このページの CodecRegistry セクションに進み、Codec を含める方法を確認します。

このセクションのクラスとインターフェースの詳細については、次の API ドキュメントを参照してください。

CodecRegistry は、指定された Java クラスをエンコードおよびデコードする Codec インスタンスの不変のコレクションです。次の CodecRegistries クラスの静的ファクトリー メソッドのいずれかを使用して、関連付けられた型に含まれる Codec インスタンスから CodecRegistry を構築できます。

  • fromCodecs()

  • fromProviders()

  • fromRegistries()

次のコード スニペットは、fromCodecs() メソッドを使用して CodecRegistry を構築する方法を示しています。

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

前の例では、 CodecRegistryに次の Codec実装が含まれています。

  • IntegerCodecIntegersを変換し、BSON パッケージの一部となるCodecです。

  • ReadStatusCodec:Java 列挙値を BSON ブール値に変換するサンプルCodec

次のコードを使用して、前の例の CodecRegistry インスタンスから Codec インスタンスを検索できます。

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

登録されていないクラスの Codec インスタンスを検索しようとすると、get() メソッドは CodecConfigurationException をスローします。

このセクションのクラスとインターフェースの詳細については、次の API ドキュメントを参照してください。

CodecProvider は、Codec インスタンスを作成し、それを CodecRegistry インスタンスに割り当てる抽象メソッドを含むインターフェースです。CodecRegistry と同様に、BSON ライブラリは get() メソッドによって検索された Codec インスタンスを使用して、Java と BSON データ型間の変換を行います。

ただし、対応する Codec オブジェクトを必要とするフィールドを含むクラスを追加する場合は、クラスの Codec をインスタンス化する前に、クラスフィールドの Codec オブジェクトをインスタンス化する必要があります。get() メソッドの CodecRegistry パラメータを使用して、Codec が依存する Codec インスタンスを渡すことができます。

次のコード例は、CodecProvider を実装して、前の例の ReadStatusCodec などの CodecRegistry インスタンスで必要な Codec インスタンスを BookCodec に渡す方法を示しています。

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

これらの Codec クラスを使用した読み取りおよび書き込み (write) 操作を示す実行可能な例については、このガイドの「カスタム コーデックの例」セクションを参照してください。

POJO を操作する場合は、よく使用されるデータ型を変換し、その動作をカスタマイズする際に重複コードを最小限に抑えるために PojoCodecProvider の使用を検討してください。詳しくは、弊社の「POJO を使用したデータのモデル化」ガイドを参照してください。

デフォルトのコーデック レジストリは、一般的に使用される Java と MongoDB の型間の変換を指定する CodecProvider クラスのセットです。別のコーデック レジストリを指定しない限り、ドライバーは自動的にデフォルトのコーデック レジストリを使用します。

1 つ以上の Codec クラスの動作をオーバーライドする必要があり、他のクラスのデフォルトのコーデック レジストリの動作を維持する場合は、優先順位に従ってすべてのレジストリを指定できます。たとえば、列挙型の Codec のデフォルトのプロバイダー動作をカスタム MyEnumCodec でオーバーライドするには、次の例に示すように、デフォルトのコーデック レジストリの前にレジストリ リストに追加する必要があります。

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

このセクションのクラスとインターフェースの詳細については、次の API ドキュメントの各セクションを参照してください。

BsonTypeClassMap クラスには、BSON typesと Java 型間の推奨マッピングが含まれています。このクラスをカスタム Codec または CodecProvider で使用すると、Document クラスなどの Iterable または Map を実装するコンテナクラスに BSON types をデコードする Java 型を管理するのに役立ちます。

新しいエントリまたは置換エントリを含む Map を渡すことにより、BsonTypeClassMap のデフォルト マッピングを追加または変更できます。

次のコード スニペットは、デフォルトの BsonTypeClassMap インスタンス内の BSON 型に対応する Java クラスの種類を検索する方法を示しています。

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

このコードは、次のように出力します。

Java type: java.util.List

BsonTypeClassMap コンストラクターで置換を指定することにより、インスタンス内のこれらのマッピングを変更できます。次の例は、BsonTypeClassMap インスタンス内の ARRAY のマッピングを 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());

このコードは、次のように出力します。

Java type: java.util.Set

デフォルトのマッピングの完全なリストについては、BsonTypeClassMap API ドキュメントを参照してください。

Tip

Document クラスが BsonTypeClassMap を使用する方法の例については、DocumentCodecProvider クラスと DocumentCodec クラスのドライバー ソースコードを参照してください。

このセクションでは、CodecCodecProvider を実装してカスタム Java クラスのエンコードおよびデコード ロジックを定義する方法を示します。また、カスタム実装を指定して使用し、挿入操作と取得操作を実行する方法も示します。

次の例では、MongoDB コレクションに保存して取り出すための Book というカスタム クラスとそのフィールドを定義しています。

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

このクラスには次のフィールドが含まれており、それぞれに Codec を割り当てる必要があります。

  • title BSON ライブラリに含まれる StringCodec を例で使用する String 値が含まれます。

  • readStatus には、本が読まれたかどうかが記述されています。例では、列挙値を BSON ブール値に変換するカスタム ReadStatusCodec を使用しています。

  • pageCount 例では BSON ライブラリに含まれる IntegerCodec を使用する Integer 値が含まれます。

次のコード例は、Book クラスに Codec を実装する方法を示しています。コンストラクターは、フィールドをエンコードおよびデコードするのに必要な Codec インスタンスを検索する CodecRegistry のインスタンスを期待していることに注意してください。

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

フィールドの Codec インスタンスを Book で使用できるようにするには、次のコード例に示すカスタム CodecProvider を実装します。

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

変換ロジックを定義した後、次の操作を実行できます。

  • Book のインスタンスのデータを MongoDB に保存する

  • MongoDB から次のインスタンスにデータを検索する Book

次の**例**クラスには、BookCodecProviderwithCodecRegistry() メソッドに渡して MongoCollection インスタンスに割り当てるコードが含まれています。このサンプル クラスでは、Book クラスと関連するコーデックを使用してデータの挿入と検索も行います。

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();
}
}
}

前の例を実行すると、出力は次のようになります。

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

このガイドで言及されているメソッドとクラスの詳細については、次のAPIドキュメントを参照してください。