문서 메뉴
문서 홈
/ / /
Java 동기화
/ /

POJO 사용자 지정

이 페이지의 내용

  • 개요
  • 포조 코덱 공급자 사용자 지정하기
  • 클래스 모델
  • 속성 모델
  • 컨벤션
  • 주석
  • BsonExtraElements 예제
  • 판별자
  • 고급 구성
  • 속성의 추상 또는 인터페이스 형식Abstract or Interface Types in Properties
  • 인수가 없는 생성자가 없는 POJO
  • 직렬화 사용자 지정

이 가이드에서는 MongoDB Java 드라이버에서 BSON과 POJO 간의 사용자 지정 데이터 변환을 정의하는 방법을 배울 수 있습니다. POJO 에 대한 가이드에서는 하나 이상의 POJO 클래스 및 해당 속성에 대한 데이터를 변환하는 방법에 대한 지침을 제공하는 클래스가 포함된 PojoCodecProvider 를 지정하는 방법을 보여줍니다.

ClassModelPropertyModel 클래스를 사용하여 데이터 변환을 지정하는 방법을 보여줍니다. 고급 구성 섹션에서 보다 구체적인 사용자 지정에 대해 알아볼 수도 있습니다.

또한 ConventionsAnnotations 와 같은 도우미를 사용하여 일반적인 serialization 작업을 지정하는 방법도 보여 줍니다.

동일한 컬렉션의 문서에 여러 개의 POJO 클래스를 직렬화하려면 판별자 섹션을 참조하세요.

조건부 직렬화를 구현해야 하거나 열거형, 제네릭, 인터페이스 유형 또는 추상 유형을 사용해야 하는 경우 고급 구성섹션을 참조하세요.

사전 정의된 동작을 사용하여 BSON과 POJO 간에 데이터를 변환하는 데만 필요한 경우 문서 데이터 형식에 표시된 PojoCodecProvider 에 대한 자동 설정을 사용할 수 있습니다: POJO 가이드에 나와 있는 에 대한 자동 설정을 사용하면 됩니다.

이 단원에서는 PojoCodecProvider 를 사용하여 데이터 변환 로직과 POJO 클래스를 지정하는 방법을 보여줍니다. PojoCodecProvider 은 데이터 변환에 사용할 코덱을 지정하는 CodecProvider 인터페이스의 구현입니다. BSON과 POJO 간의 데이터 변환을 수행할 때 이 구현을 사용하세요.

PojoCodecProvider.builder() 메서드를 사용하여 PojoCodecProvider 인스턴스를 생성할 수 있습니다. 빌더에 메소드를 연결하여 다음 중 하나를 등록할 수도 있습니다.

  • 개별 POJO 클래스

  • POJO 클래스가 포함된 패키지 이름

  • 특정 POJO 클래스에 대한 변환 로직을 설명하는 ClassModel 의 인스턴스입니다.

다음 예제에서는 " org.example.pojos " 패키지에서 POJO를 지정하는 방법을 보여 줍니다. 를 클릭하고 PojoCodecProviderCodecRegistry에 추가합니다:

import org.bson.codecs.configuration.CodecProvider;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.codecs.pojo.PojoCodecProvider;
import static org.bson.codecs.configuration.CodecRegistries.fromRegistries;
import static org.bson.codecs.configuration.CodecRegistries.fromProviders;
import static com.mongodb.MongoClientSettings.getDefaultCodecRegistry;
CodecProvider pojoCodecProvider = PojoCodecProvider.builder().register("org.example.pojos").build();
CodecRegistry pojoCodecRegistry = fromRegistries(getDefaultCodecRegistry(), fromProviders(pojoCodecProvider));
// Call withCodecRegistry(pojoCodecRegistry) on an instance of MongoClient, MongoDatabase, or MongoCollection

이 클래스에 대한 자세한 내용은 PojoCodecProvider.Builder API 설명서를 참조하세요.

ClassModel 0} 인스턴스는 특정 POJO 클래스에 대한 데이터 변환 정보를 저장합니다. 여기에는 POJO의 속성 필드를 설명하는 PropertyModel 인스턴스 목록, 필드 변환 여부, 선택 사항으로 필드를 변환할 Codecs 가 포함되어 있습니다.

ClassModel 0}에는 다음 필드가 포함되어 있습니다:

필드 이름
설명
이름
0}과 연결할 POJO 클래스 ClassModel 이름입니다.
인스턴스 크리에이터 팩토리
POJO의 새 인스턴스를 생성하는 새 인스턴스 팩토리를 포함합니다. 기본적으로 POJO에는 빈 생성자가 있어야 합니다.
PropertyModels (영문)
POJO의 필드에 대해 BSON과 데이터를 변환하는 방법을 지정하는 PropertyModel 인스턴스 목록이 포함되어 있습니다.
IdPropertyModelHolder
문서 _id 필드에 해당하는 POJO 필드를 지정합니다. 선택 사항.
판별자 키
Specifies the name of the discriminator field. Optional.
For more information on discriminators, see the Discriminators section.
판별자 값
Specifies the lookup value that represents the POJO class. Optional.
For more information on discriminators, see the Discriminators section.
판별자 깃발
판별자를 직렬화할지 여부를 지정합니다(기본적으로 꺼져 있음). 선택 사항.

이 클래스에 대한 자세한 내용은 ClassModel API 문서를 참조하세요.

ClassModel0}을 ClassModel.builder() 인스턴스화하려면 메서드를 사용하고 POJO 클래스를 지정하세요. 빌더는 리플렉션을 사용하여 필요한 메타데이터를 생성합니다.

ClassModel<Flower> classModel = ClassModel.builder(Flower.class).build();

PropertyModel 는 문서의 특정 필드를 직렬화/역직렬화하는 방법에 대한 정보를 저장합니다.

PropertyModel 0}에는 다음 정보가 포함되어 있습니다:

필드 이름
설명
이름
모델의 속성 이름을 지정합니다.
이름 읽기
BSON에 직렬화할 때 키로 사용할 프로퍼티의 이름입니다.
이름 쓰기
BSON에서 역직렬화할 때 키로 사용할 프로퍼티의 이름입니다.
데이터 입력
필드의 데이터 유형을 설명하는 org.bson.codecs.pojo.TypeData 의 인스턴스가 포함되어 있습니다.
코덱
필드를 인코딩 또는 디코딩하는 데 사용할 코덱을 지정합니다. 선택 사항.
직렬화 검사기
검사기에 지정된 기준을 사용하여 값을 직렬화할지 여부를 결정합니다.
속성 접근자
POJO에서 속성 값에 액세스하는 데 사용되는 메서드입니다.
사용 판별자
Specifies whether to use the discriminator.
For more information on discriminators, see the Discriminators section.

0}을 만들려면 메서드를 호출하여 PropertyModel 인스턴스화할 PropertyModelBuilder 수 있는 을 사용합니다.PropertyModel.builder()

이 클래스에 대한 자세한 내용은 PropertyModel.Builder API 설명서를 참조하세요.

Convention 0} 인터페이스에는 ClassModel 또는 의 동작을 수정하는 구성 옵션이 포함되어 PropertyModel 있습니다. PojoCodecProvider.Builder.conventions() 또는 ClassModelBuilder.conventions() 호출에서 Convention 을 지정할 수 있습니다.

참고

빌더는 Convention 인스턴스를 순서대로 적용하며, 이 순서는 이전에 적용된 인스턴스에서 정의된 동작을 재정의할 수 있습니다.

Conventions 클래스의 다음 정적 필드에서 BSON 라이브러리에 정의된 Convention 인스턴스에 액세스할 수 있습니다.

필드 이름
설명
ANNOTATION_CONVENTION
0} 패키지에 정의된 어노테이션을 POJO에 사용하도록 설정합니다.org.bson.codecs.pojo.annotations 자세한 내용은 주석 섹션을 참조하세요.
CLASS_AND_PROPERTY_CONVENTION
Sets the following default values for the ClassModel and PropertyModel instances:
- Discriminator key to _t
- Discriminator value to the ClassModel simple type name
- Id field to _id for each PropertyModel.
DEFAULT_CONVENTIONS
Enables the following Conventions:
- CLASS_AND_PROPERTY_CONVENTION
- ANNOTATION_CONVENTION
- OBJECT_ID_GENERATORS
NO_CONVENTIONS
빈 목록을 제공합니다.
OBJECT_ID_GENERATORS
4} 속성에서 값을 사용하는 마다 새 을 IdGenerator ObjectId 추가하는 ClassModel ObjectId id 기본 을 추가합니다.
SET_PRIVATE_FIELDS_CONVENTION
setter 메서드 없이 리플렉션을 사용하여 비공개 필드를 설정할 수 있도록 ClassModel 를 활성화합니다.
USE_GETTERS_FOR_SETTERS
세터 메서드가 없는 경우 CollectionMap 필드에 대한 세터로 게터 메서드를 사용할 수 있습니다.

다음 방법 중 하나를 사용하여 규칙을 지정할 수 있습니다:

사용자 지정 규칙을 만들려면 Convention 인터페이스를 구현하는 클래스를 만들고 ClassModelBuilder 인스턴스에 액세스할 수 있는 apply() 메서드를 재정의하세요.

POJO 클래스의 getter 및 setter 메서드에 어노테이션을 적용할 수 있습니다. 이러한 주석은 특정 필드, 메서드 또는 클래스에 대한 ClassModelPropertyModel 동작을 구성합니다.

다음 주석은 org.bson.codecs.pojo.annotations 패키지에서 사용할 수 있습니다.

주석 이름
설명
BsonCreator
Marks a public constructor or a public static method as the creator for new instances of the class. You must annotate all parameters in the constructor with either the BsonProperty or BsonId annotations.
BsonDiscriminator
클래스가 판별자를 사용하도록 지정합니다. 사용자 지정 판별자 키와 값을 설정할 수 있습니다.
BsonRepresentation
POJO 속성과 다를 때 값을 저장하는 데 사용되는 BSON types을(를) 지정합니다.
BsonId
직렬화할 프로퍼티를 _id 프로퍼티로 표시합니다.
BsonIgnore
무시할 속성을 표시합니다. 속성을 serialize 및/또는 deserialize할지 여부를 구성할 수 있습니다.
BsonProperty
POJO 필드를 BSON으로 변환할 때 사용자 지정 문서 필드 이름을 지정합니다. 필드 내에 중첩된 POJO를 직렬화하기 위해 식별자를 포함할 수 있습니다.
BsonExtraElements

필드에 매핑되지 않은 모든 요소를 역직렬화할 POJO 필드를 지정합니다. POJO 필드는 다음 유형 중 하나여야 합니다:

다음도 참조하세요.

다음 코드 스니펫은 이전 주석 중 여러 개를 사용하는 Product 이라는 샘플 POJO를 보여줍니다.

import org.bson.BsonType;
import org.bson.codecs.pojo.annotations.BsonCreator;
import org.bson.codecs.pojo.annotations.BsonDiscriminator;
import org.bson.codecs.pojo.annotations.BsonId;
import org.bson.codecs.pojo.annotations.BsonIgnore;
import org.bson.codecs.pojo.annotations.BsonProperty;
import org.bson.codecs.pojo.annotations.BsonRepresentation;
@BsonDiscriminator(value="AnnotatedProduct", key="_cls")
public class Product {
@BsonProperty("modelName")
private String name;
@BsonId()
@BsonRepresentation(BsonType.OBJECT_ID)
private String serialNumber;
@BsonIgnore
private List<Product> relatedItems;
@BsonCreator
public Product(@BsonProperty("modelName") String name) {
this.name = name;
}
// ...
}

주석을 사용할 때는 ClassModelBuilder 또는 PojoCodecProvider.BuilderConventions.ANNOTATION_CONVENTION 을 지정하는 것을 잊지 마세요. 예를 들면 다음과 같습니다.

ClassModel<Product> classModel = ClassModel.builder(Product.class).
conventions(Arrays.asList(Conventions.ANNOTATION_CONVENTION)).build();

예제 POJO의 어노테이션은 다음과 같은 동작을 지정합니다:

  • 지정된 판별자 키와 값으로 POJO를 참조하고 쓰기 작업 시 BSON 문서에 "AnnotatedProduct" 값이 있는 cls 필드를 추가합니다.

  • 문서의 POJO name 필드 및 값과 BSON modelName 필드 및 값 간 변환

  • POJO serialNumber 필드와 BSON 문서 _id 필드 값 및 문서의 값 간 변환

  • 데이터를 변환할 때 relatedItems 필드 및 값 생략

  • POJO를 인스턴스화할 때 Product(String name) 생성자 사용

@BsonExtraElements 주석을 사용하면 해당 POJO 필드 매핑이 없는 MongoDB 문서에서 데이터를 역직렬화하는 필드를 지정할 수 있습니다. 이는 애플리케이션이 부분적으로 정의된 스키마의 데이터로 작업해야 할 때 유용합니다. 이 주석을 사용하여 POJO의 필드에 해당하지 않는 모든 필드의 데이터에 액세스할 수 있습니다.

이전 예시의 제품 POJO를 사용하여 온라인 스토어에 대한 데이터를 저장하고 검색하는 상황을 생각해 보겠습니다. 스토어에 다양한 제품을 제공할수록 해당 제품을 설명하는 추가 필드가 필요하다는 것을 알게 됩니다. 각 추가 필드를 POJO에 매핑하는 대신 다음 코드 예시와 같이 @BsonExtraElements 주석이 달린 단일 필드에서 해당 필드에 액세스할 수 있습니다.

public class Product {
@BsonProperty("modelName")
private String name;
@BsonId()
@BsonRepresentation(BsonType.OBJECT_ID)
private String serialNumber;
@BsonIgnore
private List<Product> relatedItems;
@BsonExtraElements
private Document additionalInfo;
// ...

누군가가 제품 데이터에 dimensionsweight 필드를 추가하여 문서에 다음 정보가 포함되었다고 가정해 보겠습니다.

{
"name": "MDB0123",
"serialNumber": "62e2...",
"dimensions": "3x4x5",
"weight": "256g"
}

Product POJO를 사용하여 검색된 이전 문서에는 다음 데이터가 포함되어 있습니다.

ProductWithBsonExtraElements [
name=MDB0123,
serialNumber=62eb...,
relatedItems=null,
additionalInfo=Document{{dimensions=3x4x5, weight=256g}}
]

판별자는 특정 문서 스키마를 식별하는 속성입니다. 판별자 키는 스키마를 식별하는 데 사용할 문서 필드를 식별합니다. 판별자 값은 문서 필드의 기본값을 식별합니다.

판별자를 사용하여 동일한 컬렉션의 다른 객체 클래스로 역직렬화할 때 사용할 객체 클래스를 CodecProvider에 지시합니다. POJO를 MongoDB 컬렉션으로 직렬화할 때 POJO 속성 데이터에 달리 지정되지 않는 한 관련 코덱은 판별자 키-값 필드를 설정합니다.

다음 중 하나를 수행하여 POJO에서 판별자를 설정하고 활성화할 수 있습니다.

  • POJO 클래스의 판별자를 지정하려면 @BsonDiscriminator 주석을 사용하세요.

  • POJO 클래스와 연결된 ClassModelBuilder에서 enableDiscriminator(true)을 호출합니다.

@BsonDiscriminator 주석이 포함된 다음 예제 POJO 클래스와 판별자 필드가 포함된 예제 문서를 참조하세요.

@BsonDiscriminator(value="AnonymousUser", key="_cls")
public class AnonymousUser {
// class code
}
@BsonDiscriminator(value="RegisteredUser", key="_cls")
public class RegisteredUser {
// class code
}

다음은 단일 MongoDB 컬렉션의 이전 POJO에서 생성된 샘플 문서를 보여줍니다.

{ "_cls": "AnonymousUser", "_id": ObjectId("<Object ID>"), ... }
{ "_cls": "RegisteredUser", "_id": ObjectId("<Object ID>"), ... }

추상 클래스 또는 인터페이스 유형 속성을 포함하는 POJO를 직렬화하려면 해당 유형과 모든 해당 하위 유형 또는 구현에 대한 판별자를 지정해야 합니다.

필드 중 하나에서 추상 클래스 User를 참조하는 POJO를 다음과 같이 정의했다고 가정해 보겠습니다.

public class UserRecordPojo {
private User user;
// ...
}

User 추상 클래스에 하위 클래스 FreeUserSubscriberUser가 있는 경우 다음과 같이 POJO 및 추상 클래스를 CodecRegistry에 추가할 수 있습니다.

ClassModel<UserRecordPojo> userRecordPojo = ClassModel.builder(UserRecordPojo.class).enableDiscriminator(true).build();
ClassModel<User> userModel = ClassModel.builder(User.class).enableDiscriminator(true).build();
ClassModel<FreeUser> freeUserModel = ClassModel.builder(FreeUser.class).enableDiscriminator(true).build();
ClassModel<SubscriberUser> subscriberUserModel = ClassModel.builder(SubscriberUser.class).enableDiscriminator(true).build();
PojoCodecProvider pojoCodecProvider = PojoCodecProvider.builder().register(userRecordPojo, userModel, freeUserModel, subscriberUserModel).build();
CodecRegistry pojoCodecRegistry = fromRegistries(getDefaultCodecRegistry(), fromProviders(pojoCodecProvider));

판별자 지정에 대한 자세한 내용은 이 가이드의 판별자 섹션을 참조하세요 .

POJO Codecs는 기본적으로 인수가 없는 빈 생성자를 호출합니다. 다른 생성자를 지정하려면 POJO에서 다음을 수행해야 합니다.

  • ANNOTATION_CONVENTION 설정을 ClassModelBuilder에 전달합니다.

  • BsonCreator 주석을 사용하여 생성자를 식별합니다.

ANNOTATION_CONVENTION 설정에 대한 예시는 ANNOTATION_CONVENTION 예시를 참조하세요. BsonCreator 어노테이션 예시는 어노테이션 코드가 있는 POJO 예시를 참조하세요.

기본적으로 ClassModelBuilder는 POJO에서 null이 아닌 모든 속성을 직렬화하려고 시도합니다. 속성 값이 null인 경우 기본 PropertySerialization 구현에서는 해당 필드를 건너뜁니다.

다음 중 하나를 수행하여 POJO 직렬화 동작을 사용자 정의할 수 있습니다.

  • 직렬화를 항상 건너뛰려면 속성에 @BsonIgnore 주석을 사용합니다. 적절한 규칙을 사용하여 주석을 활성화해야 합니다.

  • PropertySerialization 인터페이스의 shouldSerialize() 메서드를 재정의하는 맞춤 클래스를 만듭니다. ClassModelBuilder에서 액세스할 수 있는 PropertyModelBuilder 에 사용자 정의 구현을 지정합니다.

POJO에서 @BsonIgnore 어노테이션을 사용하는 방법에 대한 자세한 내용은 이 가이드의 어노테이션 섹션을 참조하세요.

다음 샘플 코드는 필드 직렬화 여부를 결정하는 기본 조건을 재정의하기 위해 PropertySerialization 인터페이스를 구현하는 맞춤 클래스를 보여줍니다.

public class CourteousAgeSerialization implements PropertySerialization<Integer> {
@Override
public boolean shouldSerialize(Integer value) {
return (value < 30);
}
}

위 클래스는 29보다 큰 정수는 직렬화되지 않으므로 MongoDB 문서에 포함되지 않도록 지정합니다. 이 사용자 지정 직렬화 동작을 다음 샘플 POJO에 적용했다고 가정해 보겠습니다.

public class BirthdayInvitation {
private String name;
private Integer age;
private LocalDateTime eventDateTime;
// ...
}

다음 코드를 사용하여 age 필드와 연결된 ClassModel 속성에서 PropertyModelBuilderCourteousAgeSerialization 인스턴스를 추가하여 사용자 지정 직렬화를 지정할 수 있습니다.

ClassModelBuilder<BirthdayInvitation> classModel = ClassModel.builder(BirthdayInvitation.class);
((PropertyModelBuilder<Integer>) classModel.getProperty("age"))
.propertySerialization(new CourteousAgeSerialization());
PojoCodecProvider pojoCodecProvider = PojoCodecProvider.builder().register(classModel.build()).build();
CodecRegistry pojoCodecRegistry = fromRegistries(getDefaultCodecRegistry(), fromProviders(pojoCodecProvider));

age 필드에 29보다 큰 값이 포함된 POJO를 삽입하면 직렬화된 문서는 이를 생략합니다. POJO 선언 및 결과 문서는 다음과 같을 수 있습니다.

// constructor with parameters for name, age, and eventDateTime, respectively
BirthdayInvitation invitation = new BirthdayInvitation(
"Galadriel",
7582,
LocalDateTime.of(2021, Month.JANUARY, 18, 30, 0)
);

age 필드 값이 29보다 크므로 직렬화된 문서는 다음과 같아야 합니다.

{ "_id" : ObjectId("..."), "eventDateTime" : ..., "name" : "Galadriel" }

POJO Codec 사용하여 다음 기준을 충족하는 경우 일반 속성을 포함하는 클래스를 직렬화할 수 있습니다.

  • 한정된 콘크리트 유형 매개 변수만 포함

  • 해당 필드 또는 해당 필드 중 하나가 클래스 계층 구조의 일부인 경우 최상위 POJO에는 유형 매개변수가 포함되지 않습니다.

ClassModelBuilder는 유형 삭제 문제를 해결하기 위해 구체적인 유형 매개변수를 검사하고 저장합니다. 구체적인 유형 매개변수가 없는 일반 속성이 포함된 클래스를 직렬화할 수 없는데, 이는 JVM이 유형 매개변수 정보를 제거하기 때문입니다.

유형 매개변수를 저장하려면 PropertyCodecProvider 인터페이스를 구현하여 POJO에 정의된 일반 유형에 대해 이를 지정할 수 있습니다. 다음 코드 스니펫은 Guava Optional 클래스에 직렬화 호환성을 추가하는 PropertyCodecProvider의 구현 예시를 보여줍니다.

Optional 필드를 사용하여 다음 POJO를 직렬화한다고 가정해 보겠습니다.

public class ApplicationUser {
private Optional<Address> optionalAddress;
private Optional<Subscription> optionalSubscription;
// ...
}

다음 PropertyCodecProvider 구현을 사용하여 사용자 지정 코덱을 검색할 수 있습니다. 이 구현은 TypeWithTypeParameters 인터페이스를 사용하여 유형 정보에 액세스합니다.

public class OptionalPropertyCodecProvider implements PropertyCodecProvider {
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public <T> Codec<T> get(final TypeWithTypeParameters<T> type, final PropertyCodecRegistry registry) {
// Check the main type and number of generic parameters
if (Optional.class.isAssignableFrom(type.getType()) && type.getTypeParameters().size() == 1) {
// Get the codec for the concrete type of the Optional, as its declared in the POJO.
Codec<?> valueCodec = registry.get(type.getTypeParameters().get(0));
return new OptionalCodec(type.getType(), valueCodec);
} else {
return null;
}
}
private static final class OptionalCodec<T> implements Codec<Optional<T>> {
private final Class<Optional<T>> encoderClass;
private final Codec<T> codec;
private OptionalCodec(final Class<Optional<T>> encoderClass, final Codec<T> codec) {
this.encoderClass = encoderClass;
this.codec = codec;
}
@Override
public void encode(final BsonWriter writer, final Optional<T> optionalValue, final EncoderContext encoderContext) {
if (optionalValue != null && optionalValue.isPresent()) {
codec.encode(writer, optionalValue.get(), encoderContext);
} else {
writer.writeNull();
}
}
@Override
public Optional<T> decode(final BsonReader reader, final DecoderContext context) {
return Optional.of(codec.decode(reader, context));
}
@Override
public Class<Optional<T>> getEncoderClass() {
return encoderClass;
}
}
}

다음과 같이 POJO가 포함된 패키지와 PojoCodecProviderOptionalPropertyCodecProvider를 등록합니다.

CodecProvider pojoCodecProvider = PojoCodecProvider.builder()
.register("org.example.pojos")
.register(new OptionalPropertyCodecProvider())
.build();

이 섹션에 언급된 메서드 및 클래스에 대한 자세한 내용은 다음 API 문서를 참조하세요.

제네릭 및 유형 매개변수에 대한 자세한 내용 은 일반 유형 호출 및 인스턴스화에 대한 Java 언어 가이드를 참조하세요.

드라이버 버전 4.5 이상에서는 PojoCodecProvider 버전에 더 이상 enum 유형을 변환하는 코덱이 포함되어 있지 않습니다. 필요한 경우 기본 코덱 레지스트리에 있는 것과 같이 enum 유형에 대한 코덱을 등록해야 합니다.

기본 코덱 레지스트리에 포함된 코덱을 등록하는 방법에 대한 자세한 내용은 기본 코덱 레지스트리에 대한 문서를 참조하세요.

돌아가기

문서 데이터 형식: 레코드