코덱
개요
이 가이드에서는 MongoDB 코틀린(Kotlin) 드라이버에서 BSON 데이터에 대한 코틀린(Kotlin) 객체의 인코딩 및 디코딩을 처리하는 코덱 및 지원 클래스에 대해 알아볼 수 있습니다. Codec
추상화를 사용하면 모든 Kotlin 유형을 해당 BSON types에 매핑할 수 있습니다. 이를 사용하여 데이터 클래스나 Document
또는 BsonDocument
같은 중간 맵 기반 객체를 사용하는 대신 도메인 객체를 BSON에 직접 매핑할 수 있습니다.
Codec
추상화를 사용하여 맞춤 인코딩 및 디코딩 로직을 지정하는 방법을 알아보고 다음 섹션에서 구현 예시를 볼 수 있습니다.
코덱
Codec
인터페이스에는 코틀린(Kotlin) 객체를 BSON 데이터로 직렬화 및 역직렬화하기 위한 추상 메서드가 포함되어 있습니다. 이 인터페이스 구현에서 BSON과 코틀린(Kotlin) 객체 간의 변환 로직을 정의할 수 있습니다.
Codec
인터페이스를 구현하려면 encode()
, decode()
및 getEncoderClass()
추상 메서드를 재정의합니다.
이 encode()
메서드에는 다음 매개 변수가 필요합니다.
Parameter Type | 설명 |
---|---|
writer | BSON 문서 작성을 위한 메서드를 노출하는 인터페이스 유형인 BsonWriter 를 구현하는 클래스의 인스턴스입니다. 예를 들어, BsonBinaryWriter 구현은 데이터의 바이너리 스트림에 씁니다. 이 인스턴스를 사용하여 적절한 쓰기 메서드를 사용하여 BSON 값을 작성합니다. |
value | 구현에서 인코딩하는 데이터입니다. 유형은 구현에 할당된 유형 변수와 일치해야 합니다. |
encoderContext | 현재 값을 MongoDB 컬렉션에 저장할지 여부를 포함하여 BSON으로 인코딩하는 코틀린(Kotlin) 객체 데이터에 대한 메타 정보가 포함되어 있습니다. |
이 메서드는 BsonWriter
인스턴스를 사용하여 인코딩된 값을 MongoDB에 보내고 값을 반환하지 않습니다.
decode()
메서드는 BSON 데이터의 값으로 채워진 Kotlin 객체 인스턴스를 반환합니다. 이 메서드에는 다음 매개 변수가 필요합니다.
Parameter Type | 설명 |
---|---|
bsonReader | 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 }
Codec
와 해당 인스턴스가 적용되는 코틀린(Kotlin) 객체 유형 간의 매핑이 포함된 CodecRegistry
에 PowerStatusCodec
의 인스턴스를 추가할 수 있습니다. 이 페이지의 CodecRegistry 섹션으로 계속 이동하여 Codec
를 포함하는 방법을 확인합니다.
이 섹션의 클래스 및 인터페이스에 대한 자세한 내용은 다음 API 설명서를 참조하세요.
CodecRegistry
CodecRegistry
는 지정된 코틀린(Kotlin) 클래스를 인코딩하고 디코딩하는 변경이 불가능한 Codec
인스턴스 컬렉션입니다. 다음과 같은 CodecRegistries
클래스의 정적 팩토리 메서드 중 하나를 사용하여 연결된 유형에 포함된 Codec
인스턴스로부터 CodecRegistry
를 구성할 수 있습니다.
fromCodecs()
fromProviders()
fromRegistries()
다음 스니펫은 fromCodecs()
메서드를 사용하여 CodecRegistry
를 구성하는 방법을 보여 줍니다.
val codecRegistry = CodecRegistries.fromCodecs(IntegerCodec(), PowerStatusCodec())
앞의 예시에서는 CodecRegistry
에 다음과 같은 Codec
구현을 할당합니다.
IntegerCodec
Integers
를 변환하며, BSON 패키지의 일부를 구성하는Codec
입니다.PowerStatusCodec - Kotlin 열거형 값을 BSON 부울로 변환하는 샘플
Codec
입니다.
다음 코드를 사용하여 이전 예의 CodecRegistry
인스턴스에서 Codec
인스턴스를 조회할 수 있습니다.
val powerStatusCodec = codecRegistry.get(PowerStatus::class.java) val integerCodec = codecRegistry.get(Integer::class.java)
등록되지 않은 클래스의 Codec
인스턴스를 검색하려고 하면 get()
메서드에서 CodecConfigurationException
예외가 발생합니다.
이 섹션의 클래스 및 인터페이스에 대한 자세한 내용은 다음 API 설명서를 참조하세요.
CodecProvider
CodecProvider
는 Codec
인스턴스를 생성하고 이를 CodecRegistry
인스턴스에 할당하는 추상 메서드가 포함된 인터페이스입니다. CodecRegistry
과 유사하게, BSON 라이브러리는 get()
메서드로 조회된 Codec
인스턴스를 사용하여 코틀린(Kotlin)과 BSON 데이터 유형을 서로 변환합니다.
그러나 해당 Codec
객체가 필요한 필드가 포함된 클래스를 추가하는 경우 클래스의 Codec
를 인스턴스화하기 전에 클래스 필드의 Codec
객체를 인스턴스화해야 합니다. get()
메서드의 CodecRegistry
매개변수를 사용하여 Codec
가 의존하는 Codec
인스턴스를 전달할 수 있습니다.
다음 코드 예시는 CodecProvider
를 구현하여 MonolightCodec
에 필요한 Codec
인스턴스를 이전 예시의 PowerStatusCodec
과 같이 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
클래스를 사용한 읽기 및 쓰기 작업을 보여주는 실행 가능한 예시는 가이드의 사용자 지정 코덱 예시 섹션을 참조하세요.
기본 코덱 레지스트리
기본 코덱 레지스트리는 일반적으로 사용되는 Kotlin과 MongoDB 유형 간의 변환을 지정하는 CodecProvider
클래스 세트입니다. 다른 코덱 레지스트리를 지정하지 않는 한 드라이버는 자동으로 기본 코덱 레지스트리를 사용합니다.
하나 이상의 Codec
클래스 동작을 재정의하고 다른 클래스의 기본 코덱 레지스트리의 동작은 그대로 유지해야 하는 경우 모든 레지스트리를 우선 순위에 따라 지정할 수 있습니다. 예를 들어 열거형 유형에 대한 Codec
의 기본 제공자 동작을 사용자 지정 MyEnumCodec
으로 재정의하려는 경우 아래 예와 같이 기본 코덱 레지스트리 이전에 레지스트리 목록에 추가해야 합니다.
val newRegistry = CodecRegistries.fromRegistries( CodecRegistries.fromCodecs(MyEnumCodec()), MongoClientSettings.getDefaultCodecRegistry() )
이 섹션의 클래스 및 인터페이스에 대한 자세한 내용은 다음 API 설명서 섹션을 참조하세요.
BsonTypeClassMap
BsonTypeClassMap
클래스에는 BSON과 Kotlin 유형 간의 권장 매핑이 포함되어 있습니다. 사용자 지정 Codec
CodecProvider
또는 에서 이 클래스를 Kotlin 사용하면 클래스와 같이 또는 를 BSON types 구현하는 컨테이너 클래스로 을 디코딩할 유형을 관리하는 Iterable
Map
데 Document
도움이 될 수 있습니다.
새 항목이나 대체 항목이 포함된 Map
를 전달하여 BsonTypeClassMap
기본 매핑을 추가하거나 수정할 수 있습니다.
다음 코드 스니펫은 기본 BsonTypeClassMap
인스턴스에서 BSON 유형에 해당하는 코틀린(Kotlin) 클래스 유형을 검색하는 방법을 보여줍니다.
val bsonTypeClassMap = BsonTypeClassMap() val clazz = bsonTypeClassMap[BsonType.ARRAY] println("Class name: " + clazz.name)
Java type: java.util.List
BsonTypeClassMap
생성자에 대체 항목을 지정하여 인스턴스에서 이러한 매핑을 수정할 수 있습니다. 다음 코드 스니펫은 BsonTypeClassMap
인스턴스의 ARRAY
에 대한 매핑을 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)
Java type: java.util.Set
기본 매핑의 전체 목록은 BsonTypeClassMap API 문서를 참조하세요.
Document
클래스가 BsonTypeClassMap
을 사용하는 방법에 대한 예시는 다음 클래스에 대한 드라이버 소스 코드를 참조하세요.
사용자 지정 코덱 예시
이 섹션에서는 Codec
및 CodecProvider
를 구현하여 사용자 지정 코틀린 (Kotlin) 클래스에 대한 인코딩 및 디코딩 로직을 정의하는 방법을 살펴봅니다. 또한 사용자 정의 구현을 지정하고 사용하여 삽입 및 검색 작업을 수행하는 방법도 짚어 봅니다.
팁
코틀린(Kotlin) 직렬화
사용자 지정 코덱을 구현하는 대신 코틀린 (Kotlin) 직렬화를 사용하여 @Serializable
클래스로 데이터 인코딩 및 디코딩을 처리하다 할 수 있습니다. 프레임워크 에 이미 익숙하거나 관용적 인 코틀린 (Kotlin) 접근 방식을 사용하는 것을 선호하는 경우 코틀린 (Kotlin) 직렬화를 선택할 수 있습니다. 자세한 내용은 코틀린 (Kotlin) 직렬화 문서를 참조하세요.
다음 코드 스니펫은 Monolight
사용자 정의 클래스와 MongoDB 컬렉션에서 저장하고 검색하려는 필드의 예시를 보여줍니다.
data class Monolight( var powerStatus: PowerStatus = PowerStatus.OFF, var colorTemperature: Int? = null ) { override fun toString(): String = "Monolight [powerStatus=$powerStatus, colorTemperature=$colorTemperature]" }
이 클래스에는 다음과 같은 필드가 있으며, 각 필드에 Codec
을 할당해야 합니다.
powerStatus
특정 열거형 값을 BSON 부울로 변환하는 PowerStatusCodec을 사용하는 표시등이 "켜짐" 또는 "꺼짐"으로 전환되는지 여부를 설명합니다.colorTemperature
조명의 색상을 설명하고 BSON 라이브러리에 포함된IntegerCodec
을 사용하는Int
값을 포함합니다.
다음 코드 예시는 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 { 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 } }
전환 로직을 정의한 후에는 다음을 수행할 수 있습니다.
Monolight
인스턴스의 데이터를 MongoDB에 저장MongoDB에서 인스턴스로 데이터 검색
Monolight
다음 예시 클래스에는 MonolightCodecProvider
를 withCodecRegistry()
메서드에 전달하여 MongoCollection
인스턴스에 할당하는 코드가 포함되어 있습니다. 또한 예시 클래스는 Monolight
클래스 및 관련 코덱을 사용하여 데이터를 삽입하고 검색합니다.
fun main() = runBlocking { val mongoClient = MongoClient.create("<connection string uri>") val codecRegistry = CodecRegistries.fromRegistries( CodecRegistries.fromCodecs(IntegerCodec(), PowerStatusCodec()), CodecRegistries.fromProviders(MonolightCodecProvider()), MongoClientSettings.getDefaultCodecRegistry() ) val database = mongoClient.getDatabase("codecs_example_products") val collection = database.getCollection<Monolight>("monolights") .withCodecRegistry(codecRegistry) // Construct and insert an instance of Monolight val myMonolight = Monolight(PowerStatus.ON, 5200) collection.insertOne(myMonolight) // Retrieve one or more instances of Monolight val lights = collection.find().toList() println(lights) }
[Monolight [powerStatus=ON, colorTemperature=5200]]
이 섹션에 언급된 메서드 및 클래스에 대한 자세한 내용은 다음 API 문서를 참조하세요.