Docs Menu
Docs Home
/ / /
Java 동기화
/ /

코덱

이 페이지의 내용

  • 개요
  • 코덱
  • CodecRegistry
  • CodecProvider
  • 기본 코덱 레지스트리
  • BsonTypeClassMap
  • 사용자 지정 코덱 예제

이 가이드에서는 MongoDB Java 드라이버에서 BSON 데이터에 대한 Java 객체의 인코딩 및 디코딩을 처리하는 코덱과 지원 클래스에 대해 알아볼 수 있습니다. Codec 추상화(abstraction)를 사용하면 모든 Java 유형을 해당 BSON types에 매핑할 수 있습니다. 이를 사용하여 Document 또는 BsonDocument 같은 중간 맵 기반 객체를 사용하는 대신 도메인 객체를 BSON에 직접 매핑할 수 있습니다.

Codec 추상화를 사용하여 맞춤 인코딩 및 디코딩 로직을 지정하는 방법을 알아보고 다음 섹션에서 구현 예제를 볼 수 있습니다.

  • 코덱

  • CodecRegistry

  • CodecProvider

  • 사용자 지정 코덱 예제

일반 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> {
@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;
}
}

PowerStatusCodec의 인스턴스를CodecRegistry에 추가할 수 있으며 여기에는 Codec과 해당 인스턴스가 적용되는 Java 객체 유형 간의 매핑이 포함되어 있습니다. 이 페이지의 코덱 레지스트리 섹션으로 진행하여 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 문자열을 BSON 부울로 변환하는 샘플 Codec입니다.

다음 코드를 사용하여 이전 예의 CodecRegistry 인스턴스에서 Codec 인스턴스를 조회할 수 있습니다.

Codec<String> powerStatusCodec = codecRegistry.get(String.class);
Codec<Integer> integerCodec = codecRegistry.get(Integer.class);

등록되지 않은 클래스의 Codec 인스턴스를 검색하려고 하면 get() 메서드에서 CodecConfigurationException 예외가 발생합니다.

이 섹션의 클래스 및 인터페이스에 대한 자세한 내용은 다음 API 설명서를 참조하세요.

CodecProviderCodec 인스턴스를 생성하여 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() {}
@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 클래스를 사용한 읽기 및 쓰기 작업을 보여주는 실행 가능한 예시는 가이드의 사용자 지정 코덱 예시 섹션을 참조하세요.

POJO로 작업할 때는 PojoCodecProvider 를 사용하여 중복 코드를 최소화하여 일반적으로 사용되는 데이터 유형을 변환하고 해당 동작을 맞춤 설정합니다. 자세한 내용은 POJO 맞춤 설정 가이드를 참조하세요.

기본 코덱 레지스트리는 일반적으로 사용되는 Java 및 MongoDB 유형 간의 변환을 지정하는 CodecProvider 클래스 세트입니다. 다른 코덱 레지스트리를 지정하지 않는 한 드라이버는 자동으로 기본 코덱 레지스트리를 사용합니다.

하나 이상의 Codec 클래스 동작을 재정의하고 다른 클래스의 기본 코덱 레지스트리의 동작은 그대로 유지해야 하는 경우 모든 레지스트리를 우선 순위에 따라 지정할 수 있습니다. 예를 들어 열거형 유형에 대한 Codec의 기본 제공자 동작을 사용자 지정 MyEnumCodec으로 재정의하려는 경우 아래 예와 같이 기본 코덱 레지스트리 이전에 레지스트리 목록에 추가해야 합니다.

CodecRegistry newRegistry = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(new MyEnumCodec()),
MongoClientSettings.getDefaultCodecRegistry());

이 섹션의 클래스 및 인터페이스에 대한 자세한 내용은 다음 API 설명서 섹션을 참조하세요.

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을 사용하는 방법에 대한 예시는 다음 클래스에 대한 드라이버 소스 코드를 참조하세요.

이 섹션에서는 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 사용자 지정