코덱
개요
이 가이드에서는 MongoDB Java 드라이버에서 BSON 데이터에 대한 Java 객체의 인코딩 및 디코딩을 처리하는 코덱과 지원 클래스에 대해 알아볼 수 있습니다. Codec
추상화(abstraction)를 사용하면 모든 Java 유형을 해당 BSON types에 매핑할 수 있습니다. 이를 사용하여 Document
또는 BsonDocument
같은 중간 맵 기반 객체를 사용하는 대신 도메인 객체를 BSON에 직접 매핑할 수 있습니다.
Codec
추상화를 사용하여 맞춤 인코딩 및 디코딩 로직을 지정하는 방법을 알아보고 다음 섹션에서 구현 예시를 볼 수 있습니다.
기존 Java 객체(POJO)에 대한 인코딩 및 디코딩 로직을 맞춤 설정하려는 경우 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 불(boolean) 값으로 변환하기 위해 Codec
을 구현합니다. encode()
메서드는 PowerStatus
를 BSON 불(boolean)로 변환하고 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; } }
PowerStatusCodec
의 인스턴스를CodecRegistry
에 추가할 수 있으며 여기에는 Codec
과 해당 인스턴스가 적용되는 Java 객체 유형 간의 매핑이 포함되어 있습니다. 이 페이지의 코덱 레지스트리 섹션으로 진행하여 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 문자열을 BSON 부울로 변환하는 샘플
Codec
입니다.
다음 코드를 사용하여 이전 예의 CodecRegistry
인스턴스에서 Codec
인스턴스를 조회할 수 있습니다.
Codec<String> powerStatusCodec = codecRegistry.get(String.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
를 구현하여 MonolightCodec
에 필요한 Codec
인스턴스를 이전 예시의 PowerStatusCodec
과 같이 CodecRegistry
인스턴스에 전달하는 방법을 보여 줍니다:
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
클래스를 사용한 읽기 및 쓰기 작업을 보여주는 실행 가능한 예시는 가이드의 사용자 지정 코덱 예시 섹션을 참조하세요.
POJO로 작업할 때는 PojoCodecProvider
를 사용하여 중복 코드를 최소화하여 일반적으로 사용되는 데이터 유형을 변환하고 해당 동작을 맞춤 설정합니다. 자세한 내용은 POJO 맞춤 설정 가이드를 참조하세요.
기본 코덱 레지스트리
기본 코덱 레지스트리는 일반적으로 사용되는 Java 및 MongoDB 유형 간의 변환을 지정하는 CodecProvider
클래스 세트입니다. 다른 코덱 레지스트리를 지정하지 않는 한 드라이버는 자동으로 기본 코덱 레지스트리를 사용합니다.
하나 이상의 Codec
클래스 동작을 재정의하고 다른 클래스의 기본 코덱 레지스트리의 동작은 그대로 유지해야 하는 경우 모든 레지스트리를 우선 순위에 따라 지정할 수 있습니다. 예를 들어 열거형 유형에 대한 Codec
의 기본 제공자 동작을 사용자 지정 MyEnumCodec
으로 재정의하려는 경우 아래 예와 같이 기본 코덱 레지스트리 이전에 레지스트리 목록에 추가해야 합니다.
CodecRegistry newRegistry = CodecRegistries.fromRegistries( CodecRegistries.fromCodecs(new MyEnumCodec()), MongoClientSettings.getDefaultCodecRegistry());
이 섹션의 클래스 및 인터페이스에 대한 자세한 내용은 다음 API 설명서 섹션을 참조하세요.
BsonTypeClassMap
BsonTypeClassMap
클래스에는 BSON과 Java 유형 간의 권장 매핑이 포함되어 있습니다. 맞춤 설정한 Codec
또는 CodecProvider
에서 이 클래스를 사용하면 Document
클래스와 같이 Iterable
또는 Map
을 구현하는 컨테이너 클래스에서 BSON 유형을 디코딩할 Java 유형을 관리하는 데 도움이 됩니다.
새 항목이나 대체 항목이 포함된 Map
를 전달하여 BsonTypeClassMap
기본 매핑을 추가하거나 수정할 수 있습니다.
다음 코드 스니펫은 기본 BsonTypeClassMap
인스턴스의 BSON types에 해당하는 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
및 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); } 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(); } 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; } 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 문서를 참조하세요.