コーデック
Overview
このガイドでは、MongoDB Java ドライバーで Java オブジェクトと BSON データのエンコードとデコードを処理する Codec とサポート クラスについて学習できます。Codec
抽象化を使用すると、任意の Java 型を対応する BSON 型にマップできます。これを使用すると、Document
や BsonDocument
などの中間マップベースのオブジェクトを使用する代わりに、ドメイン オブジェクトを BSON との間で直接マップできます。
次のセクションでは、Codec
抽象化を使用してカスタム エンコードおよびデコード ロジックを指定する方法と、実装例を確認する方法について説明します。
POJO(Plain Old Java Object)のエンコードおよびデコード ロジックをカスタマイズする場合は、 POJO カスタマイズ に関するガイドをお読みください。
コーデック
Codec
インターフェースには、Java オブジェクトを BSON データにシリアル化および逆シリアル化するための抽象メソッドが含まれています。このインターフェースの実装では、BSON と Java オブジェクト間の変換ロジックを定義できます。
Codec
インターフェースを実装するには、encode()
、decode()
、および getEncoderClass()
抽象メソッドをオーバーライドします。
encode()
メソッドには次のパラメーターが必要です。
Parameter Type | 説明 |
---|---|
| BSON ドキュメントを書込むためのメソッドを公開するインターフェース型である |
| 実装によってエンコードされるデータ。型は、実装に割り当てられた型変数と一致する必要があります。 |
| 現在の値を MongoDB コレクションに保存するかどうかなど、BSON にエンコードされる Java オブジェクト データに関するメタ情報が含まれます。 |
このメソッドは、BsonWriter
インスタンスを使用してエンコードされた値を MongoDB に送信し、値を返しません。
decode()
メソッドは、BSON データから取得した値が設定された Java オブジェクト インスタンスを返します。このメソッドには次のパラメータが必要です。
Parameter Type | 説明 |
---|---|
| BSON ドキュメントを読み取るためのメソッドを公開するインターフェース型である |
| 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> { public void encode(BsonWriter writer, PowerStatus value, EncoderContext encoderContext) { if (value != null) { writer.writeBoolean(value.equals(PowerStatus.ON) ? Boolean.TRUE : Boolean.FALSE); } } public PowerStatus decode(BsonReader reader, DecoderContext decoderContext) { return reader.readBoolean() ? PowerStatus.ON : PowerStatus.OFF; } public Class<PowerStatus> getEncoderClass() { return PowerStatus.class; } }
Codec
とそれが適用される Java オブジェクトタイプとの間のマッピングを含むPowerStatusCodec
のインスタンスをCodecRegistry
に追加できます。 このページの「 CodecRegistry」セクションに進み、 Codec
を含める方法を確認します。
このセクションのクラスとインターフェースの詳細については、次の API ドキュメントを参照してください。
CodecRegistry
CodecRegistry
は、指定された Java クラスをエンコードおよびデコードする Codec
インスタンスの不変のコレクションです。次の CodecRegistries
クラスの静的ファクトリー メソッドのいずれかを使用して、関連付けられた型に含まれる Codec
インスタンスから CodecRegistry
を構築できます。
fromCodecs()
fromProviders()
fromRegistries()
次のコード スニペットは、fromCodecs()
メソッドを使用して CodecRegistry
を構築する方法を示しています。
CodecRegistry codecRegistry = CodecRegistries.fromCodecs(new IntegerCodec(), new PowerStatusCodec());
前の例では、CodecRegistry
に次の Codec
実装を割り当てています。
IntegerCodec
、Integers
を変換し、BSON パッケージの一部となるCodec
です。PowerStatusCodec 、特定の Java string を BSON ブール値に変換するサンプル
Codec
。
次のコードを使用して、前の例の CodecRegistry
インスタンスから Codec
インスタンスを検索できます。
Codec<PowerStatus> powerStatusCodec = codecRegistry.get(PowerStatus.class); Codec<Integer> integerCodec = codecRegistry.get(Integer.class);
登録されていないクラスの Codec
インスタンスを検索しようとすると、get()
メソッドは CodecConfigurationException
の例外をスローします。
このセクションのクラスとインターフェースの詳細については、次の API ドキュメントを参照してください。
CodecProvider
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() {} 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 カスタマイズ ガイド」を参照してください。
Default Codec Registry
デフォルトのコーデック レジストリは、一般的に使用される Java と MongoDB の型間の変換を指定する CodecProvider
クラスのセットです。別のコーデック レジストリを指定しない限り、ドライバーは自動的にデフォルトのコーデック レジストリを使用します。
1 つ以上の Codec
クラスの動作をオーバーライドする必要があり、他のクラスのデフォルトのコーデック レジストリの動作を維持する場合は、優先順位に従ってすべてのレジストリを指定できます。たとえば、列挙型の Codec
のデフォルトのプロバイダー動作をカスタム MyEnumCodec
でオーバーライドする場合は、次の例に示すように、デフォルトのコーデック レジストリの前にそれをレジストリ リストに追加する必要があります。
CodecRegistry newRegistry = CodecRegistries.fromRegistries( CodecRegistries.fromCodecs(new MyEnumCodec()), MongoClientSettings.getDefaultCodecRegistry());
このセクションのクラスとインターフェースの詳細については、次の API ドキュメントの各セクションを参照してください。
BsonTypeClassMap
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
を使用する方法の例については、次のクラスのドライバー ソース コードを参照してください。
カスタム Codec の例
このセクションでは、Codec
と CodecProvider
を実装して、カスタム 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); } // Defines an encode() method to convert Monolight enum values to BSON values 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(); } // Defines a decode() method to convert BSON values to Monolight enum values 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; } // Returns an instance of the Monolight class, since Java cannot infer the class type public Class<Monolight> getEncoderClass() { return Monolight.class; } }
フィールドの Codec
インスタンスを Monolight
で使用できるようにするには、次のコード例に示すカスタム CodecProvider
を実装します。
public class MonolightCodecProvider implements CodecProvider { public MonolightCodecProvider() {} 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
次のサンプル クラスには、MonolightCodecProvider
を withCodecRegistry()
メソッドに渡して 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 ドキュメントを参照してください。