カスタム変換

次の Spring Converter 実装の例は、String からカスタム Email 値オブジェクトに変換します。

@ReadingConverter
public class EmailReadConverter implements Converter<String, Email> {

  public Email convert(String source) {
    return Email.valueOf(source);
  }
}

ソースとターゲットの型がネイティブ型である Converter を記述した場合、それを読み取りコンバーターと見なすか、書き込みコンバーターと見なすべきかを判断できません。コンバーターインスタンスを両方として登録すると、望ましくない結果が生じる可能性があります。例: Converter<String, Long> があいまいですが、書き込み時にすべての String インスタンスを Long インスタンスに変換しようとしても意味がありません。インフラストラクチャーにコンバーターを一方向にのみ登録させるために、コンバーターの実装で使用される @ReadingConverter および @WritingConverter アノテーションを提供します。

インスタンスはクラスパスまたはコンテナースキャンから取得されないため、コンバーターは明示的な登録の対象となります。変換サービスへの不要な登録と、そのような登録に起因する副作用を回避するためです。コンバーターは、ソースおよびターゲットの型に基づいて、登録されたコンバーターの登録および照会を可能にする中央機能として CustomConversions に登録されます。

CustomConversions には、事前に定義された一連のコンバーター登録が付属しています。

  • java.timejava.util.DateString 型間の変換用の JSR-310 コンバーター。

ローカルテンポラル型(LocalDateTime から java.util.Date など)のデフォルトコンバーターは、システムデフォルトのタイムゾーン設定に依存して、これらの型間で変換します。独自のコンバーターを登録することにより、デフォルトのコンバーターをオーバーライドできます。

コンバーターの明確化

一般に、Converter の実装は、変換元と変換先のソース型とターゲット型をインスペクションします。これらの 1 つが、基になるデータアクセス API がネイティブに処理できる型かどうかに応じて、コンバーターインスタンスを読み取りまたは書き込みコンバーターとして登録します。次の例は、書き込みコンバーターと読み取りコンバーターを示しています(違いは Converter の修飾子の順序にあることに注意してください)。

// Write converter as only the target type is one that can be handled natively
class MyConverter implements Converter<Person, String> { … }

// Read converter as only the source type is one that can be handled natively
class MyConverter implements Converter<String, Person> { … }

型ベースのコンバーター

マッピング結果に影響を与える最も簡単なメソッドは、@Field アノテーションを介して目的のネイティブ MongoDB ターゲット型を指定することです。これにより、値をネイティブ org.bson.types.Decimal128 形式で保持しながら、ドメインモデルで BigDecimal などの非 MongoDB 型を操作できるようになります。

例 1: 明示的なターゲット型のマッピング
public class Payment {

  @Id String id; (1)

  @Field(targetType = FieldType.DECIMAL128) (2)
  BigDecimal value;

  Date date; (3)

}
{
  "_id"   : ObjectId("5ca4a34fa264a01503b36af8"), (1)
  "value" : NumberDecimal(2.099), (2)
  "date"   : ISODate("2019-04-03T12:11:01.870Z") (3)
}
1 有効な ObjectId を表す文字列 ID 値は自動的に変換されます。詳細については、_id フィールドがマッピング層でどのように処理されるかを参照してください。
2 目的のターゲット型は Decimal128 として明示的に定義されており、これは NumberDecimal に変換されます。それ以外の場合、BigDecimal 値は String に切り詰められます。
3Date 値は MongoDB ドライバー自体によって処理され、ISODate として保存されます。

上記のスニペットは、単純な型のヒントを提供するのに便利です。マッピングプロセスをよりきめ細かく制御するには、Spring コンバーターを MappingMongoConverter などの MongoConverter 実装に登録できます。

MappingMongoConverter は、オブジェクト自体のマップを試みる前に、Spring コンバーターが特定のクラスを処理できるかどうかを確認します。パフォーマンスの向上やその他のカスタムマッピングのニーズのために、MappingMongoConverter の通常のマッピング戦略を「ハイジャック」するには、まず Spring Converter インターフェースの実装を作成し、それを MappingConverter に登録する必要があります。

Spring 型変換サービスの詳細については、こちらのリファレンスドキュメントを参照してください。

ライティングコンバーター

次の例は、Person オブジェクトから org.bson.Document に変換する Converter の実装を示しています。

import org.springframework.core.convert.converter.Converter;

import org.bson.Document;

public class PersonWriteConverter implements Converter<Person, Document> {

  public Document convert(Person source) {
    Document document = new Document();
    document.put("_id", source.getId());
    document.put("name", source.getFirstName());
    document.put("age", source.getAge());
    return document;
  }
}

読み取りコンバーター

次の例は、Document オブジェクトから Person オブジェクトに変換する Converter の実装を示しています。

public class PersonReadConverter implements Converter<Document, Person> {

  public Person convert(Document source) {
    Person p = new Person((ObjectId) source.get("_id"), (String) source.get("name"));
    p.setAge((Integer) source.get("age"));
    return p;
  }
}

コンバーターの登録

class MyMongoConfiguration extends AbstractMongoClientConfiguration {

	@Override
	public String getDatabaseName() {
		return "database";
	}

	@Override
	protected void configureConverters(MongoConverterConfigurationAdapter adapter) {
		adapter.registerConverter(new com.example.PersonReadConverter());
		adapter.registerConverter(new com.example.PersonWriteConverter());
	}
}