2.2. シリアル化のコンテキストイニシャライザーの作成
シリアル化コンテキストイニシャライザーを使用すると、Data Grid で以下を登録することができます。
- ユーザータイプを記述する Protobuf スキーマ。
- シリアル化およびデシリアライズ機能を提供するマーシャラー。
概略としては、以下の操作を行いシリアル化コンテキストイニシャライザーを作成する必要があります。
- ProtoStream アノテーションを Java クラスに追加します。
-
Data Grid が提供する ProtoStream プロセッサーを使用して、
SerializationContextInitializer
実装をコンパイルします。
org.infinispan.protostream.MessageMarshaller
インターフェイスは非推奨となり、ProtoStream の今後のバージョンで削除される予定です。完全に削除されるまで MessageMarshaller
の使用方法を示すコード例またはドキュメントは無視する必要があります。
2.2.1. ProtoStream プロセッサーの追加
Data Grid は、コンパイル時にクラスの Java アノテーションを処理する ProtoStream プロセッサーアーティファクトを提供し、Protobuf スキーマ、付随マーシャラー、および SerializationContextInitializer
インターフェイスの具体的な実装を生成します。
手順
pom.xml
のmaven-compiler-plugin
のアノテーションプロセッサー設定にprotostream-processor
を追加します。<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>...</version> <configuration> <annotationProcessorPaths> <annotationProcessorPath> <groupId>org.infinispan.protostream</groupId> <artifactId>protostream-processor</artifactId> <version>...</version> </annotationProcessorPath> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build>
2.2.2. ProtoStream アノテーションの Java クラスへの追加
Java クラスとそのメンバーにアノテーションを追加して ProtoStream メタデータを宣言します。次に、Data Grid は ProtoStream プロセッサーを使用して Protobuf スキーマと、それらのアノテーションから関連するマーシャラーを生成します。
手順
フィールドで直接、または getter メソッドまたは setter メソッドのいずれかで、
@ProtoField
でマーシャリングする Java フィールドにアノテーションを付けます。Java クラスのアノテーションが付けられていないフィールドは一時的です。たとえば、Java クラスに 15 つのフィールドがあり、それらのうち 5 つにアノテーションを付けるとします。作成されるスキーマにはこれらの 5 つのフィールドのみが含まれ、これらの 5 つのフィールドのみが Data Grid にクラスインスタンスを保存するときにマーシャリングされます。
-
@ProtoFactory
を使用して、イミュータブルオブジェクトのコンストラクターにアノテーションを付けます。アノテーションが付けられたコンストラクターは@ProtoField
アノテーションが付けられたフィールドをすべて初期化する必要があります。 -
@ProtoEnumValue
で Java 列挙型のメンバーにアノテーションを付けます。
以下の Author.java
および Book.java
の例は、@ProtoField
および @ProtoFactory
のアノテーションが付けられた Java クラスを示しています。
Author.java
import org.infinispan.protostream.annotations.ProtoFactory; import org.infinispan.protostream.annotations.ProtoField; public class Author { @ProtoField(1) final String name; @ProtoField(2) final String surname; @ProtoFactory Author(String name, String surname) { this.name = name; this.surname = surname; } // public Getter methods omitted for brevity }
Book.java
import org.infinispan.protostream.annotations.ProtoFactory; import org.infinispan.protostream.annotations.ProtoField; public class Book { @ProtoField(number = 1) public final UUID id; @ProtoField(number = 2) final String title; @ProtoField(number = 3) final String description; @ProtoField(number = 4, defaultValue = "0") final int publicationYear; @ProtoField(number = 5, collectionImplementation = ArrayList.class) final List<Author> authors; @ProtoField(number = 6) public Language language; @ProtoFactory Book(UUID id, String title, String description, int publicationYear, List<Author> authors, Language language) { this.id = id; this.title = title; this.description = description; this.publicationYear = publicationYear; this.authors = authors; this.language = language; } // public Getter methods not included for brevity }
以下の Language.java
の例は、対応する Protobuf スキーマとともに @ProtoEnumValue
アノテーションが付けられた Java 列挙を示しています。
Language.java
import org.infinispan.protostream.annotations.ProtoEnumValue; public enum Language { @ProtoEnumValue(number = 0, name = "EN") ENGLISH, @ProtoEnumValue(number = 1, name = "DE") GERMAN, @ProtoEnumValue(number = 2, name = "IT") ITALIAN, @ProtoEnumValue(number = 3, name = "ES") SPANISH, @ProtoEnumValue(number = 4, name = "FR") FRENCH; }
Language.proto
enum Language { EN = 0; DE = 1; IT = 2; ES = 3; FR = 4; }
2.2.3. ProtoStream アダプタークラスの作成
ProtoStream は @ProtoAdapter
アノテーションを提供し、これを使用して、直接アノテーションを付けることができない外部のサードパーティーの Java オブジェクトクラスをマーシャリングすることができます。
手順
Adapter
クラスを作成し、以下の例のように@ProtoAdapter
アノテーションを追加します。import java.util.UUID; import org.infinispan.protostream.annotations.ProtoAdapter; import org.infinispan.protostream.annotations.ProtoFactory; import org.infinispan.protostream.annotations.ProtoField; import org.infinispan.protostream.descriptors.Type; /** * Human readable UUID adapter for UUID marshalling */ @ProtoAdapter(UUID.class) public class UUIDAdapter { @ProtoFactory UUID create(String stringUUID) { return UUID.fromString(stringUUID); } @ProtoField(1) String getStringUUID(UUID uuid) { return uuid.toString(); } }
2.2.4. シリアル化コンテキストイニシャライザーの生成
ProtoStream プロセッサーを追加して Java クラスにアノテーションを付けると、Data Grid が Protobuf スキーマ、付随するマーシャラー、および SerializationContextInitializer
の具体的な実装を生成するように、@ProtoSchema
アノテーションをインターフェイスに追加できます。
デフォルトでは、生成された実装名は "Impl" 接尾辞が付いたアノテーション付きクラス名です。
手順
GeneratedSchema
を拡張するインターフェイスまたはそのスーパーインターフェイスSerializationContextInitializer
を定義します。注記GeneratedSchema
インターフェイスには Protobuf スキーマにアクセスするためのメソッドが含まれていますが、SerializationContextInitializer
インターフェイスは登録メソッドのみをサポートします。-
インターフェイスに
@ProtoSchema
アノテーションを付けます。 -
includeClasses
パラメーターには、生成されたSerializationContextInitializer
実装のすべてのクラスが含まれることを確認します。 -
schemaFileName
パラメーターで、生成された.proto
スキーマの名前を指定します。 -
schemaFilePath
パラメーターで、スキーマファイルが生成されるtarget/classes
の下にパスを設定します。 -
schemaPackageName
パラメーターで、生成された.proto
スキーマのパッケージ名を指定します。
次の例は、@ProtoSchema
でアノテーションが付けられた GeneratedSchema
インターフェイスを示しています。
@ProtoSchema( includeClasses = { Book.class, Author.class, UUIDAdapter.class, Language.class }, schemaFileName = "library.proto", schemaFilePath = "proto/", schemaPackageName = "book_sample") interface LibraryInitializer extends GeneratedSchema { }
次のステップ
組み込みキャッシュを使用する場合は、Data Grid は SerializationContextInitializer
実装を自動的に登録します。
リモートキャッシュを使用する場合は、SerializationContextInitializer
実装を Data Grid Server に登録する必要があります。
2.2.5. Protocol Buffers のベストプラクティス
Protocol Buffers のドキュメントには、下位互換性を維持するためにメッセージを設計する方法とスキーマを 進化させる 方法に関する ベストプラクティス のリストが記載されています。
Data Grid は、スキーマが更新されたときに自動的に互換性チェックを実行し、非互換性が検出された場合は更新を拒否できます。チェックの種類は、グローバル serialization
設定の schema-compatibility
属性を介して設定できます。利用可能なレベルは次のとおりです。
-
UNRESTRICTED
: チェックは実行されない -
LENIENT
: ルールのサブセットが適用される -
STRICT
: すべてのルールが適用される (デフォルト)
次の表は、各レベルで有効になっている互換性チェックルールを示しています。
ルール | 説明 | レベル |
---|---|---|
予約フィールドを使用しない | 現在の定義と更新された定義を比較し、メッセージの以前に予約されたフィールドまたは ID が同じメッセージの一部として使用されている場合は、警告のリストを返します。 |
|
フィールド ID の変更なし | 現在の定義と更新された定義を比較し、フィールド ID 番号が変更されている場合は、警告のリストを返します。 |
|
フィールドタイプを変更なし | 現在の定義と更新された定義を比較し、フィールドタイプが変更されている場合は、警告のリストを返します。 |
|
予約なしでフィールドを削除しない | 現在の定義と更新された定義を比較し、フィールド名または ID の対応する予約なしにフィールドが削除された場合は、警告のリストを返します。 |
|
予約フィールドを削除しない | 現在の定義と更新された定義を比較し、予約済みフィールドが削除されている場合は、警告のリストを返します。 |
|
フィールド名を変更しない | 現在の定義と更新された定義を比較し、メッセージの以前のフィールドの名前が変更されている場合は、警告のリストを返します。 |
|
2.2.6. シリアル化コンテキストイニシャライザーの登録
組み込みキャッシュの場合、Data Grid は java.util.ServiceLoader
を使用してアノテーションが付けられた SerializationContextInitializer
実装にシリアル化コンテキストおよびマーシャラーを自動的に登録します。
必要に応じて、SerializationContextInitializer
実装の自動登録を無効にして、手動で登録することができます。
1 つの SerializationContextInitializer
実装を手動で登録する場合は、自動登録が無効になります。その後、他のすべての実装を手動で登録する必要があります。
手順
ProtoSchema.service
アノテーションの値をfalse
に設定します。@ProtoSchema( includeClasses = SomeClass.class, ... service = false )
-
以下の例のように、プログラムまたは宣言的に
SerializationContextInitializer
実装を手動で登録します。
宣言的
<serialization> <context-initializer class="org.infinispan.example.LibraryInitializerImpl"/> <context-initializer class="org.infinispan.example.another.SCIImpl"/> </serialization>
プログラマティック
GlobalConfigurationBuilder builder = new GlobalConfigurationBuilder(); builder.serialization() .addContextInitializers(new LibraryInitializerImpl(), new SCIImpl());
2.2.7. Data Grid Server への Protobuf スキーマの登録
Ickle クエリーを実行する場合、または application/x-protostream
から application/json
などの他のメディアタイプに変換する場合は、Data Grid Server に Protobuf スキーマを登録する必要があります。
前提条件
ProtoStream プロセッサーで Protobuf スキーマを生成します。
生成された Protobuf スキーマは、
target/<schemaFilePath>/
ディレクトリーにあります。CREATE
権限を持つユーザーを用意します。注記セキュリティー認可には、スキーマを追加するための
CREATE
権限が必要です。デフォルト設定では、少なくともdeployer
のロールが必要です。
手順
次のいずれかの方法で、Protobuf スキーマを Data Grid サーバーに追加します。
- 任意のブラウザーで Data Grid コンソールを開き、Schema タブを選択してから Add Protobuf schema を選択します。
Data Grid コマンドラインインターフェイス (CLI) から
--upload=
引数を指定してschema
コマンドを使用します。schema --upload=person.proto person
REST API を使用して、
POST
要求のペイロードに Protobuf スキーマを含めます。POST/rest/v2/schemas/<schema_name>
以下の例のように、Hot Rod クライアントで生成された
SerializationContextInitializer
実装を使用して、Protobuf スキーマを登録します。/** * Register generated Protobuf schema with Data Grid Server. * This requires the RemoteCacheManager to be initialized. * * @param initializer The serialization context initializer for the schema. */ private void registerSchemas(SerializationContextInitializer initializer) { // Store schemas in the '___protobuf_metadata' cache to register them. // Using ProtobufMetadataManagerConstants might require the query dependency. final RemoteCache<String, String> protoMetadataCache = remoteCacheManager.getCache(ProtobufMetadataManagerConstants.PROTOBUF_METADATA_CACHE_NAME); // Add the generated schema to the cache. protoMetadataCache.put(initializer.getProtoFileName(), initializer.getProtoFile()); // Ensure the registered Protobuf schemas do not contain errors. // Throw an exception if errors exist. String errors = protoMetadataCache.get(ProtobufMetadataManagerConstants.ERRORS_KEY_SUFFIX); if (errors != null) { throw new IllegalStateException("Some Protobuf schema files contain errors: " + errors + "\nSchema :\n" + initializer.getProtoFileName()); } }
SerializationContextInitializer
実装およびカスタムクラスを持つ JAR ファイルを$RHDG_HOME/server/lib
ディレクトリーに追加します。これを実行すると、Data Grid Server は起動時に Protobuf スキーマを登録します。ただし、スキーマは
___protobuf_metadata
キャッシュに保存されたり、クラスター全体で自動的に分散されたりしないため、アーカイブを各サーバーインストールに追加する必要があります。注記Data Grid Server が
application/x-protostream
からapplication/x-java-object
への変換を実施する必要がある場合、これを実行する必要があります。この場合、POJO 用の JAR ファイルも追加する必要があります。
次のステップ
以下の例のように、SerializationContextInitializer
を Hot Rod クライアントに登録します。
ConfigurationBuilder remoteBuilder = new ConfigurationBuilder(); remoteBuilder.addServer().host(host).port(Integer.parseInt(port)); // Add your generated SerializationContextInitializer implementation. LibraryInitalizer initializer = new LibraryInitalizerImpl(); remoteBuilder.addContextInitializer(initializer);
2.2.8. 手動によるシリアル化コンテキストイニシャライザーの実装
Data Grid は、SerializationContextInitializer
または GeneratedSchema
インターフェイスを手動で実装しないことを強く推奨します。
ProtobufTagMarshaller
および RawProtobufMarshaller
アノテーションを使用して SerializationContextInitializer
または GeneratedSchema
インターフェイスを手動で実装できます。
ただし、手動の実装には多くの面倒なオーバーヘッドが必要で、エラーが発生する可能性が高くなります。protostream-processor
アーティファクトを使用して生成する実装は、ProtoStream マーシャリングを設定するより効率的で信頼できる方法です。