Docs Menu
Docs Home
/ / /
Java 同期
/ /

コーデック

項目一覧

  • Overview
  • コーデック
  • CodecRegistry
  • CodecProvider
  • Default Codec Registry
  • BsonTypeClassMap
  • カスタム Codec の例

このガイドでは、MongoDB Java ドライバーで Java オブジェクトと BSON データのエンコードとデコードを処理する Codec とサポート クラスについて学習できます。Codec 抽象化を使用すると、任意の Java 型を対応する BSON 型にマップできます。これを使用すると、DocumentBsonDocument などの中間マップベースのオブジェクトを使用する代わりに、ドメイン オブジェクトを BSON との間で直接マップできます。

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

  • コーデック

  • CodecRegistry

  • CodecProvider

  • カスタム Codec の例

POJO(Plain Old Java Object)のエンコードおよびデコード ロジックをカスタマイズする場合は、 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 を実装する方法を示す次のコード例を参照してください。

PowerStatus 列挙型には、電気スイッチの状態を表す値「ON」と「OFF」が含まれています。

public enum PowerStatus {
ON,
OFF
}

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

public class PowerStatusCodec implements Codec<PowerStatus> {
@Override
public void encode(BsonWriter writer, PowerStatus value, EncoderContext encoderContext) {
if (value != null) {
writer.writeBoolean(value.equals(PowerStatus.ON) ? Boolean.TRUE : Boolean.FALSE);
}
}
@Override
public PowerStatus decode(BsonReader reader, DecoderContext decoderContext) {
return reader.readBoolean() ? PowerStatus.ON : PowerStatus.OFF;
}
@Override
public Class<PowerStatus> getEncoderClass() {
return PowerStatus.class;
}
}

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

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

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

  • fromCodecs()

  • fromProviders()

  • fromRegistries()

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

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

前の例では、CodecRegistry に次の Codec 実装を割り当てています。

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

  • PowerStatusCodec 、特定の Java string を BSON ブール値に変換するサンプルCodec

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

Codec<String> powerStatusCodec = codecRegistry.get(String.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 を実装して、前の例の PowerStatusCodec などの CodecRegistry インスタンスで必要な Codec インスタンスを MonolightCodec に渡す方法を示しています。

public class MonolightCodecProvider implements CodecProvider {
public MonolightCodecProvider() {}
@Override
@SuppressWarnings("unchecked")
public <T> Codec<T> get(Class<T> clazz, CodecRegistry registry) {
if (clazz == Monolight.class) {
return (Codec<T>) new MonolightCodec(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 ドキュメント。

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

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

次のコード スニペットは、Monolight というカスタム クラスの例と、MongoDB コレクションに保存および検索するフィールドを示しています。

public class Monolight {
private PowerStatus powerStatus = PowerStatus.OFF;
private Integer colorTemperature;
public Monolight() {}
// ...

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

  • powerStatus ライトが"オン" に切り替えられたか"オフ" に切り替えられたかを示します。そのために、特定の列挙値を BSON ブール値に変換する PowerStatusCodec を使用します。

  • colorTemperature は、ライトの色を記述し、BSON ライブラリに含まれる IntegerCodec を使用する Integer 値が含まれます。

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

public class MonolightCodec implements Codec<Monolight>{
private Codec<PowerStatus> powerStatusCodec;
private Codec<Integer> integerCodec;
public MonolightCodec(CodecRegistry registry) {
this.powerStatusCodec = registry.get(PowerStatus.class);
this.integerCodec = registry.get(Integer.class);
}
@Override
public void encode(BsonWriter writer, Monolight value, EncoderContext encoderContext) {
writer.writeStartDocument();
writer.writeName("powerStatus");
powerStatusCodec.encode(writer, value.getPowerStatus(), encoderContext);
writer.writeName("colorTemperature");
integerCodec.encode(writer, value.getColorTemperature(), encoderContext);
writer.writeEndDocument();
}
@Override
public Monolight decode(BsonReader reader, DecoderContext decoderContext) {
Monolight monolight = new Monolight();
reader.readStartDocument();
while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
String fieldName = reader.readName();
if (fieldName.equals("powerStatus")) {
monolight.setPowerStatus(powerStatusCodec.decode(reader, decoderContext));
} else if (fieldName.equals("colorTemperature")) {
monolight.setColorTemperature(integerCodec.decode(reader, decoderContext));
} else if (fieldName.equals("_id")){
reader.readObjectId();
}
}
reader.readEndDocument();
return monolight;
}
@Override
public Class<Monolight> getEncoderClass() {
return Monolight.class;
}
}

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

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

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

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

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

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

public class MonolightCodecExample {
public static void main(String[] args) {
String uri = "<MongoDB connection URI>";
try (MongoClient mongoClient = MongoClients.create(uri)) {
CodecRegistry codecRegistry = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(new IntegerCodec(), new PowerStatusCodec()),
CodecRegistries.fromProviders(new MonolightCodecProvider()),
MongoClientSettings.getDefaultCodecRegistry());
MongoDatabase database = mongoClient.getDatabase("codecs_example_products");
MongoCollection<Monolight> collection = database.getCollection("monolights", Monolight.class).withCodecRegistry(codecRegistry);
// construct and insert an instance of Monolight
Monolight myMonolight = new Monolight();
myMonolight.setPowerStatus(PowerStatus.ON);
myMonolight.setColorTemperature(5200);
collection.insertOne(myMonolight);
// retrieve one or more instances of Monolight
List<Monolight> lights = new ArrayList<>();
collection.find().into(lights);
System.out.println(lights);
}
}
}

上記の例を実行すると、次の出力が表示されます。

[Monolight [powerStatus=ON, colorTemperature=5200]]

このセクションで説明されるメソッドとクラスの詳細については、次の API ドキュメントを参照してください。

戻る

POJO カスタマイズ