Docs Menu
Docs Home
/ / /
Kotlin Sync ドライバー
/

コーデック

項目一覧

  • Overview
  • コーデック
  • encode() メソッド
  • デコード() メソッド
  • CodecRegistry
  • CodecProvider
  • Default Codec Registry
  • BsonTypeClassMap
  • カスタム Codec の例

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

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

  • コーデック

  • CodecRegistry

  • CodecProvider

  • カスタム Codec の例

Tip

Kotlin 直列化

Kotlin シリアル化では、カスタム コーデックを実装する代わりに@Serializableクラスを使用してデータのエンコードとデコードを処理できます。 kotlinx.serializationライブラリにすでに知識がある場合、または慣用的な Kotlin アプローチを使用したい場合は、 Kotlin シリアル化を選択することをお勧めします。 詳しくは、 Kotlin 直列化のガイドを参照してください。

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

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

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

Parameter Type
説明
writer
BSON ドキュメントを書込むためのメソッドを公開するインターフェース型である BsonWriter を実装するクラスのインスタンス。たとえば、BsonBinaryWriter 実装はバイナリ ストリームのデータに書込みます。このインスタンスを使用して、適切な書込みメソッドで BSON 値を書込みます。
value
実装によってエンコードされるデータ。型は、実装に割り当てられた型変数と一致する必要があります。
encoderContext
現在の値を MongoDB コレクションに保存するかどうかなど、BSON にエンコードされる Kotlin オブジェクト データに関するメタ情報が含まれます。

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

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

Parameter Type
説明
reader
BSON ドキュメントを読み取るためのメソッドを公開するインターフェース型である BsonReader を実装するクラスのインスタンス。たとえば、BsonBinaryReader 実装はバイナリ ストリームのデータから読み取ります。
decoderContext
Kotlin オブジェクトにデコードされる BSON データに関する情報が含まれます。

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

このセクションでは、カスタムCodecインターフェースを実装する方法を示すコード例が含まれています。

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

enum class PowerStatus {
ON,
OFF
}

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

class PowerStatusCodec : Codec<PowerStatus> {
override fun encode(
writer: BsonWriter, value: PowerStatus, encoderContext: EncoderContext
) = writer.writeBoolean(value == PowerStatus.ON)
override fun decode(
reader: BsonReader, decoderContext: DecoderContext)
: PowerStatus {
return when (reader.readBoolean()) {
true -> PowerStatus.ON
false -> PowerStatus.OFF
}
}
override fun getEncoderClass(): Class<PowerStatus> = PowerStatus::class.java
}

PowerStatusCodecCodecRegistryのインスタンスを に追加できます。レジストリにCodecを含める方法については、このページの [ CodecRegistry]セクションを表示してください。

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

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

  • fromCodecs(): Codecインスタンスからレジストリを作成します

  • fromProviders(): CodecProviderインスタンスからレジストリを作成します

  • fromRegistries(): CodecRegistryインスタンスからレジストリを作成します

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

val codecRegistry = CodecRegistries
.fromCodecs(IntegerCodec(), PowerStatusCodec())

上記の例では、 CodecRegistryに次のCodec実装が割り当てられています。

  • IntegerCodec:Codec Integersを変換するこれは、BSON パッケージの一部です。

  • PowerStatusCodec: Kotlin 列挙値を BSON ブール値に変換する前のセクションのサンプルCodec

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

val powerStatusCodec = codecRegistry.get(PowerStatus::class.java)
val integerCodec = codecRegistry.get(Integer::class.java)

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

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

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

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

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

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

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

val newRegistry = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(MyEnumCodec()),
MongoClientSettings.getCodecRegistry()
)

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

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

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

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

val bsonTypeClassMap = BsonTypeClassMap()
val clazz = bsonTypeClassMap[BsonType.ARRAY]
println("Kotlin class name: " + clazz.name)
Kotlin class name: java.util.List

BsonTypeClassMapコンストラクターで置換を指定することにより、インスタンス内のこれらのマッピングを変更できます。 次のコード スニペットは、 BsonTypeClassMapインスタンス内の BSON 配列型のマッピングをSetクラスに置き換える方法を示しています。

val replacements = mutableMapOf<BsonType, Class<*>>(BsonType.ARRAY to MutableSet::class.java)
val bsonTypeClassMap = BsonTypeClassMap(replacements)
val clazz = bsonTypeClassMap[BsonType.ARRAY]
println("Class name: " + clazz.name)
Kotlin class name: java.util.Set

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

このセクションでは、Codec CodecProviderインターフェースと インターフェースを実装して、カスタム Kotlin クラスのエンコードおよびデコード ロジックを定義する方法を示します。カスタム実装を指定して使用し、読み取りおよび書込み操作を実行する方法を示します。

次のコードは、サンプル データ クラスMonolightを定義します。

data class Monolight(
var powerStatus: PowerStatus = PowerStatus.OFF,
var colorTemperature: Int? = null
) {
override fun toString():
String = "Monolight { powerStatus: $powerStatus, colorTemperature: $colorTemperature }"
}

このクラスには次のフィールドが含まれており、エンコードとデコードを処理するために対応するCodecがそれぞれに必要です。

  • powerStatus: デバイスのライトが"ON"であるか、 "OFF"であるかを表します。 このフィールドには、 PowerStatus列挙値を BSON ブール値に変換するPowerStatusCodecを使用します。

  • colorTemperature: デバイスライトの色をキロメートル単位で記述し、 Int値として記述します。 このフィールドには、BSON ライブラリで提供されているIntegerCodecを使用します。

次のコードは、 MonolightクラスにCodecを実装する方法を示しています。 コンストラクターは、クラス フィールドのエンコードとデコードに必要なCodecインスタンスを検索するCodecRegistryのインスタンスを期待しています。

class MonolightCodec(registry: CodecRegistry) : Codec<Monolight> {
private val powerStatusCodec: Codec<PowerStatus>
private val integerCodec: Codec<Int>
init {
powerStatusCodec = registry[PowerStatus::class.java]
integerCodec = IntegerCodec()
}
override fun encode(writer: BsonWriter, value: Monolight, encoderContext: EncoderContext) {
writer.writeStartDocument()
writer.writeName("powerStatus")
powerStatusCodec.encode(writer, value.powerStatus, encoderContext)
writer.writeName("colorTemperature")
integerCodec.encode(writer, value.colorTemperature, encoderContext)
writer.writeEndDocument()
}
override fun decode(reader: BsonReader, decoderContext: DecoderContext): Monolight {
val monolight = Monolight()
reader.readStartDocument()
while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
when (reader.readName()) {
"powerStatus" -> monolight.powerStatus =
powerStatusCodec.decode(reader, decoderContext)
"colorTemperature" -> monolight.colorTemperature =
integerCodec.decode(reader, decoderContext)
"_id" -> reader.readObjectId()
}
}
reader.readEndDocument()
return monolight
}
override fun getEncoderClass(): Class<Monolight> = Monolight::class.java
}

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

class MonolightCodecProvider : CodecProvider {
@Suppress("UNCHECKED_CAST")
override fun <T> get(clazz: Class<T>, registry: CodecRegistry): Codec<T>? {
return if (clazz == Monolight::class.java) {
MonolightCodec(registry) as Codec<T>
} else null // Return null when not a provider for the requested class
}
}

変換ロジックを定義した後、次のアクションを実行できます。

  • MongoDB でMonolightのインスタンスを保存する

  • 次のインスタンスとして MongoDB からドキュメントを取得: Monolight

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

val mongoClient = MongoClient.create(uri)
val codecRegistry = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(IntegerCodec(), PowerStatusCodec()),
CodecRegistries.fromProviders(MonolightCodecProvider()),
MongoClientSettings.getDefaultCodecRegistry()
)
val database = mongoClient.getDatabase("codec_test")
val collection = database.getCollection<Monolight>("monolights")
.withCodecRegistry(codecRegistry)
// Insert instances of Monolight
val monolights = listOf(
Monolight(PowerStatus.ON, 5200),
Monolight(PowerStatus.OFF, 3000)
)
collection.insertMany(monolights)
// Retrieve instances of Monolight
val results = collection.find()
results.forEach { l ->
println(l)
}
Monolight { powerStatus: ON, colorTemperature: 5200 }
Monolight { powerStatus: OFF, colorTemperature: 3000 }

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

戻る

Kotlin 直列化