5.2. AutoProtoSchemaBuilder アノテーションへのアプリケーションの移行


以前のバージョンの DataGrid は、ProtoStream API の MessageMarshaller インターフェイスを使用してマーシャリングを設定します。

MessageMarshaller API と ProtoSchemaBuilder アノテーションはどちらも、ProtoStream4.3.4 に対応する DataGrid 8.1.1 で非推奨になりました。

MessageMarshaller インターフェイスの使用には、以下のいずれかが含まれます。

  • Protobuf スキーマを手動で作成します。
  • ProtoSchemaBuilder アノテーションを Java クラスに追加してから、Protobuf スキーマを生成します。

ただし、ProtoStream マーシャリングを設定するためのこれらの手法は、 Data Grid 8.1.1 以降で使用可能な AutoProtoSchemaBuilder アノテーションほど効率的で信頼性が高くありません。AutoProtoSchemaBuilder アノテーションを Java クラスに追加し、Protobuf スキーマと関連するマーシャラーを含む SerializationContextInitializer 実装を生成するだけです。

Red Hat は、AutoProtoSchemaBuilder アノテーションの使用を開始して、ProtoStream マーシャラーから最良の結果を取得することを推奨します。

次のコード例は、アプリケーションを MessageMarshaller API から AutoProtoSchemaBuilder アノテーションに移行する方法を示しています。

5.2.1. 基本的な MessageMarshaller の実装

この例には、デフォルト以外のタイプを使用するいくつかのフィールドが含まれています。コードジェネレーターはデフォルトで int 型を使用するため、text フィールドの順序は異なり、fixed32 フィールドは生成された Protobuf スキーマタイプと競合します。

SimpleEntry.java

public class SimpleEntry {

  private String description;
  private Collection<String> text;
  private int intDefault;
  private Integer fixed32;

  // public Getter, Setter, equals and HashCode methods omitted for brevity
}

SimpleEntryMarshaller.java

import org.infinispan.protostream.MessageMarshaller;

public class SimpleEntryMarshaller implements MessageMarshaller<SimpleEntry> {

  @Override
  public void writeTo(ProtoStreamWriter writer, SimpleEntry testEntry) throws IOException {
    writer.writeString("description", testEntry.getDescription());
    writer.writeInt("intDefault", testEntry.getIntDefault());
    writer.writeInt("fix32", testEntry.getFixed32());
    writer.writeCollection("text", testEntry.getText(), String.class);
  }

  @Override
  public SimpleEntry readFrom(MessageMarshaller.ProtoStreamReader reader) throws IOException {
    SimpleEntry x = new SimpleEntry();

    x.setDescription(reader.readString("description"));
    x.setIntDefault(reader.readInt("intDefault"));
    x.setFixed32(reader.readInt("fix32"));
    x.setText(reader.readCollection("text", new LinkedList<String>(), String.class));

    return x;
  }
}

結果の Protobuf スキーマ

syntax = "proto2";

package example;

message SimpleEntry {
   required string description = 1;
   optional int32 intDefault = 2;
   optional fixed32 fix32 = 3;
   repeated string text = 4;
}

AutoProtoSchemaBuilder アノテーションに移行

SimpleEntry.java

import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.descriptors.Type;

public class SimpleEntry {

  private String description;
  private Collection<String> text;
  private int intDefault;
  private Integer fixed32;

  @ProtoField(number = 1)
  public String getDescription() {...}

  @ProtoField(number = 4, collectionImplementation = LinkedList.class)
  public Collection<String> getText() {...}

  @ProtoField(number = 2, defaultValue = "0")
  public int getIntDefault() {...}

  @ProtoField(number = 3, type = Type.FIXED32)
  public Integer getFixed32() {...}

  // public Getter, Setter, equals and HashCode methods and convenient constructors omitted for brevity
}

SimpleEntryInitializer.java

import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;

@AutoProtoSchemaBuilder(includeClasses = { SimpleEntry.class }, schemaFileName = "simple.proto", schemaFilePath = "proto", schemaPackageName = "example")
public interface SimpleEntryInitializer extends GeneratedSchema {
}

重要な所見
  • Field 2 は、以前のバージョンの ProtoStream マーシャラーがチェックしなかった int として定義されています。
  • Java int フィールドは null 許容ではないため、ProtoStream プロセッサーは失敗します。
    Java int フィールドは、required または defaultValue で初期化する必要があります。

    Java アプリケーションの観点からは、int フィールドは 0 で初期化されるため、put 操作で設定されるため、影響を与えることなく defaultValue を使用できます。required への変更は、常に存在する場合、保存されたデータの観点からは問題ではありませんが、さまざまなクライアントで問題が発生する可能性があります。

  • 互換性を確立するため、Field 3 は、Type.FIXED32 に明示的に設定する必要があります。
  • テキストコレクションは、結果の Protobuf スキーマに対して正しい順序で設定する必要があります。
重要

Protobuf スキーマのテキストコレクションの順序は、移行の前後で同じである必要があります。同様に、移行中に fixed32 タイプを設定する必要があります。

そうでない場合、クライアントアプリケーションは次の例外を出力し、起動に失敗する可能性があります。

Exception ( ISPN004034: Unable to unmarshall bytes )

また、キャッシュされたデータに不完全または不正確な結果が表示される場合もあります。

5.2.2. カスタムタイプを使用した MessageMarshaller の実装

このセクションでは、ProtoStream がネイティブに処理しないフィールドを含む MessageMarshaller 実装の移行例を示します。

次の例では BigInteger クラスを使用していますが、データグリッドアダプターやカスタムクラスを含め、すべてのクラスに適用されます。

注記

BigInteger クラスは不変であるため、引数のないコンストラクターはありません。

CustomTypeEntry.java

import java.math.BigInteger;

public class CustomTypeEntry {

  final String description;
  final BigInteger bigInt;

  // public Getter, Setter, equals and HashCode methods and convenient constructors omitted for brevity
}

CustomTypeEntryMarshaller.java

import org.infinispan.protostream.MessageMarshaller;

public class CustomTypeEntryMarshaller implements MessageMarshaller<CustomTypeEntry> {

  @Override
  public void writeTo(ProtoStreamWriter writer, CustomTypeEntry testEntry) throws IOException {
    writer.writeString("description", testEntry.description);
    writer.writeString("bigInt", testEntry.bigInt.toString());
  }

  @Override
  public CustomTypeEntry readFrom(MessageMarshaller.ProtoStreamReader reader) throws IOException {
    final String desc = reader.readString("description");
    final BigInteger bInt = new BigInteger(reader.readString("bigInt"));

    return new CustomTypeEntry(desc, bInt);
  }
}

CustomTypeEntry.proto

syntax = "proto2";

package example;

message CustomTypeEntry {
   required string description = 1;
   required string bigInt = 2;
}

アダプタークラスを使用して移行されたコード

ProtoAdapter アノテーションを使用して、MessageMarshaller 実装で作成した Protobuf スキーマと互換性のある Protobuf スキーマを生成する方法で CustomType クラスをマーシャリングできます。

このアプローチでは、次のことができます。

  • CustomTypeEntry クラスにアノテーションを追加してはなりません。
  • @ProtoAdapter アノテーションを使用して Protobuf スキーマとマーシャラーの生成方法を制御する CustomTypeEntryAdapter クラスを作成します。
  • @AutoProtoSchemaBuilder アノテーションとともに CustomTypeEntryAdapter クラスを含めます。

    注記

    AutoProtoSchemaBuilder アノテーションは CustomTypeEntry クラスを参照しないため、そのクラスに含まれるアノテーションはすべて無視されます。

次の例が示す CustomTypeEntry クラスの ProtoStream アノテーションを含む CustomTypeEntryAdapter クラス:

CustomTypeEntryAdapter.java

import java.math.BigInteger;

import org.infinispan.protostream.annotations.ProtoAdapter;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;

@ProtoAdapter(CustomTypeEntry.class)
public class CustomTypeEntryAdapter {

  @ProtoFactory
  public CustomTypeEntry create(String description, String bigInt) {
    return new CustomTypeEntry(description, new BigInteger(bigInt));
  }

  @ProtoField(number = 1, required = true)
  public String getDescription(CustomTypeEntry t) {
    return t.description;
  }

  @ProtoField(number = 2, required = true)
  public String getBigInt(CustomTypeEntry t) {
    return t.bigInt.toString();
  }
}

次の例が示す CustomTypeEntryAdapter クラスを参照する AutoProtoSchemaBuilder アノテーションと t もに SerializationContextInitializer を示しています。

CustomTypeEntryInitializer.java

import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;

@AutoProtoSchemaBuilder(includeClasses = { CustomTypeEntryAdapter.class },
   schemaFileName = "custom.proto",
   schemaFilePath = "proto",
   schemaPackageName = "example")
public interface CustomTypeAdapterInitializer extends GeneratedSchema { }

アダプタークラスなしで移行されたコード

アダプタークラスを作成する代わりに、ProtoStream アノテーションを CustomTypeEntry クラスに直接追加できます。

重要

この例では、生成された Protobuf スキーマは、BigInteger が別個のメッセージであるため、MessageMarshaller インターフェイスを介して追加されたキャッシュ内のデータと互換性がありません。アダプターフィールドに同じ文字列が書き込まれていても、データのマーシャリングを解除することはできません。

次の例が示す直接 ProtoStream アノテーションを含む CustomTypeEntry クラス:

CustomTypeEntry.java

import java.math.BigInteger;

public class CustomTypeEntry {

  @ProtoField(number = 1)
  final String description;
  @ProtoField(number = 2)
  final BigInteger bigInt;

  @ProtoFactory
  public CustomTypeEntry(String description, BigInteger bigInt) {
    this.description = description;
    this.bigInt = bigInt;
  }

  // public Getter, Setter, equals and HashCode methods and convenient constructors omitted for brevity
}

以下の例は、CustomTypeEntry および BigIntegerAdapter クラスを参照する AutoProtoSchemaBuilder アノテーションと共に SerializationContextInitializer を示しています。

CustomTypeEntryInitializer.java

import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.types.java.math.BigIntegerAdapter;

@AutoProtoSchemaBuilder(includeClasses = { CustomTypeEntry.class,
   BigIntegerAdapter.class },
   schemaFileName = "customtype.proto",
   schemaFilePath = "proto",
   schemaPackageName = "example")
public interface CustomTypeInitializer extends GeneratedSchema { }

前述の SerializationContextInitializer 実装から Protobuf スキーマを生成すると、以下の Protobuf スキーマになります。

CustomTypeEntry.proto

syntax = "proto2";

package example;

message BigInteger {
   optional bytes bytes = 1;
}

message CustomTypeEntry {
   optional string description = 1;
   optional BigInteger bigInt = 2;
}

Red Hat logoGithubRedditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

Red Hat ドキュメントについて

Red Hat をお使いのお客様が、信頼できるコンテンツが含まれている製品やサービスを活用することで、イノベーションを行い、目標を達成できるようにします。 最新の更新を見る.

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

© 2024 Red Hat, Inc.