27 Portable Object Formatの使用

Portable Object Format (POF)を使用して、Coherenceで使用するJavaオブジェクトをシリアライズできます。

.NETおよびC++拡張クライアントを構築する際のPOFの操作方法の詳細は、Oracle Coherenceリモート・クライアントの開発.NETクライアントの統合オブジェクトの構築およびC++クライアントの統合オブジェクトの構築を参照してください。

この章の内容は次のとおりです。

POFシリアライズの概要

シリアライズとは、オブジェクトをバイナリ形式にエンコードするプロセスです。ネットワークを介してデータを移動する必要があるため、これはCoherenceの操作に不可欠なコンポーネントです。POFは言語に依存しないバイナリ形式です。POFは領域と時間の両方において効率的であり、Coherenceの基礎となる技術です。PIF-POFバイナリ形式を参照してください。

シリアライズで使用可能なオプションには、標準Javaシリアライズ、POF、独自のカスタム・シリアライズ・ルーチンなどいくつかあります。各オプションには、それぞれトレードオフがあります。標準Javaシリアライズは簡単に実装可能であり、循環オブジェクト・グラフをサポートし、オブジェクトIDを保持します。ただし、比較的動作が低速で、冗長なバイナリ形式が使用され、Javaオブジェクトのみが処理対象となります。

POFには、次の利点があります。

  • 現在はJava、.NETおよびC++をサポートしており、言語に依存しません。

  • 非常に効率的です。1つのString、1つのlongおよび3つのintを備えた簡単なテスト・クラスでは、標準のJavaシリアライズと比較して、シリアライズおよびデシリアライズが7倍高速化され、生成されるバイナリのサイズが1/6になります。

  • バージョニングが可能です。オブジェクトの向上を図ることが可能であり、上位および下位の互換性があります。

  • シリアライズ・ロジックを外部化できます。

  • 索引付けされ、オブジェクト全体をデシリアライズせずに値を抽出できます。POFエクストラクタとPOFアップデータの使用を参照してください。

ポータブル・タイプについて

Coherence Feature Packリリース14.1.1.2206では、ポータブル・タイプが導入されています。これにより、シリアライズ・コードを手動で実装する必要なく、注釈を使用してPOFシリアライズのサポートをクラスに追加する方法が提供されます。

POFは、純粋なJavaアプリケーションを記述する場合に推奨されるシリアライズ形式です。理由は次のとおりです。
  • JavaシリアライズやExternalizableLiteなど、サポートされている他のシリアライズ形式よりも大幅に高速です。
  • サポートされている他のシリアライズ形式よりも大幅にコンパクトで、特定のサイズのクラスタに多くのデータを格納し、ネットワーク経由で移動するデータを減らすことができます。
  • データ・クラスのシームレスな進化をサポートしているため、アプリケーションの様々な部分(記憶域メンバーとクライアントの両方)を相互に独立してアップグレードでき、その過程でデータを失うリスクはありません。

長年にわたり、POFはほとんど変更されていませんでしたが、Coherence 3.5 (2009)でPOFリフレクションが導入され、PofNavigatorを介してPOFストリームから個々の属性を抽出できるようになりました。POFエクストラクタとPOFアップデータの使用を参照してください。

POF注釈の実装は、POFのパフォーマンス上の利点に影響するJavaリフレクションに依存しています。これらの制限により、従来のPOF注釈は、このリリースで非推奨になりました。この機能は、現在、ポータブル・タイプに置き換えられています。

この項には次のトピックが含まれます:

ポータブル・タイプの機能および利点

ポータブル・タイプは、次の点でPOF注釈とは異なります。
  • POF注釈と同様に、シリアライズ・コードを手動で実装する必要なく、注釈を使用してPOFシリアライズのサポートをクラスに追加する方法を提供します。
  • バイト・コード・インストゥルメンテーションを使用してコンパイル時にシリアライズ・コードを実装し、実行時にJavaリフレクションに依存しません。このJavaへの非依存性により、手動で実装されたシリアライズ・コードと同様に高速ですが、エラーが発生しやすくなります。
  • POF構成ファイルを介した明示的な登録は、サポートしますが、必要ありません。これは、POFタイプ登録に必要なすべてのメタデータ(タイプ識別子、使用するシリアライザ・クラスなど)が@PortableType注釈ですでに使用可能であるためです。
  • クラスの進化を完全にサポートします。

実際、ポータブル・タイプは、Evolvableインタフェースの手動実装よりも優れた、完全な進化のサポートを提供します。

Evolvableインタフェースの制限の1つは、クラス階層内のリーフ・クラスの進化のみをサポートすることです。ポータブル・タイプにはこの制限はなく、階層内のクラスを進化させるだけでなく、クラス階層の任意のレベルに新しいクラスを追加することによって、クラス階層自体を進化させることができます。

使用方法の基本の理解

ポータブル・タイプの基本的な要件は2つのみです。
  • クラスには@PortableType注釈を付ける必要があります
  • シリアライズする必要があるフィールドには、@Portableまたは関連する注釈(@PortableDate@PortableArray@PortableSet@PortableListまたは@PortableMap)のいずれかで注釈を付ける必要があります
    @PortableType(id = 1)
    public class Pet
        {
        @Portable
        protected String name;
    
        // constructors, accessors, etc.
        }
    
    @PortableType(id = 2)
    public class Dog extends Pet
        {
        @Portable
        private String breed;
    
        // constructors, accessors, etc.
        }

ノート:

注釈付きでないフィールドは一時的なものと見なされます。

その他の属性レベルの注釈を使用すると、属性のタイプに固有の特定のシリアライズ動作を制御できます。

たとえば、@PortableDateを使用すると、(modeプロパティを使用して) java.util.Dateインスタンスをシリアライズするときに日付、時刻またはその両方をシリアライズするかどうか、および(includeTimezoneプロパティを使用して)タイムゾーン情報を含めるかどうかを制御できます。

Java 8 (またはそれ以降)のjava.timeクラスを使用している場合は、かわりに@Portable注釈を使用して、クラス自体からこの情報を導出できます。たとえば、LocalTimeはタイム・ゾーン情報を持たない時刻のみとしてシリアライズされ、OffsetDateTimeはタイム・ゾーン情報を持つ日付と時刻の両方としてシリアライズされます。

同様に、配列、コレクションおよびマップをシリアライズする場合、POFでは共通エンコーディングを使用できます。これは、要素の型(マップの場合はキーまたは値の型、あるいはその両方)が、コレクションの各要素に対して1回ではなく、POFストリームに1回のみ書き込まれるため、よりコンパクトなシリアライズ形式となります。

public class MyClass
    {
    @PortableArray(elementClass = String.class)
    private String[] m_stringArray;

    @PortableSet(elementClass = String.class, clazz = LinkedHashSet.class)
    private Set<String> m_setOfStrings;

    @PortableList(elementClass = String.class)
    private List<String> m_listOfStrings;

    @PortableMap(keyClass = Integer.class, valueClass = String.class, clazz = TreeMap.class)
    private Map<Integer, String> m_uniformMap;
    }

前述の例からわかるように、これらの注釈を使用すると、特定の属性のデシリアライズ中に作成される具体的なクラスを指定することもできます。clazzプロパティを指定しない場合、HashSetがデフォルトのセットの型、ArrayListがデフォルトのリストの型、HashMapがデフォルトのマップの型として使用されます。

クラスのバージョニングおよび進化

Coherenceは分散システムであり、すべてのクラスタ・メンバー、およびクラスタに接続するすべてのクライアント・プロセスが、各クラスとすべてのクラスの同じバージョンを持っている保証はありません。実際、ローリング・アップグレードを使用してダウンタイムを回避するシステムには、これが当てはまります。

また、クラスタとすべてのクライアントを同時にアップグレードすることは、安全でも実用的でもありません。したがって、クラスタ・メンバーとクライアント間で同じクラスの異なるバージョンを許容できることは、望ましいだけでなく、多くの人にとって必要なことです。

問題は、古いバージョンのクラスを持つプロセスが、同じクラスの新しいバージョンから作成されたシリアライズ・データを読み取る場合、何も認識しない属性がいくつか発生する可能性があることです。クラッシュするのではなく、それらを無視して、必要で認識している属性を読み取れるようにすることが理想的です。しかし、それでは問題の一部しか解決しません。プロセスが不明な属性を完全に無視した場合、一部の属性のみを認識している古いバージョンのクラスをシリアライズして同じデータを書き戻すと、プロセスは以前に受信したが何も認識しないデータを失います。

明らかに、これは長期的なデータ記憶域を目的としたシステムにとって望ましいシナリオではありません。POFでは、様々なクラスタおよびクライアント・プロセスに同じクラスのバージョンがいくつ存在するかに関係なく、またどのプロセスがデータを読み書きするかに関係なく、データが失われないことを保証する方法で、クラスの進化をサポートします。クラスの進化のサポートは、Evolvableインタフェースを介して最初からPOFで行われていましたが、ポータブル・タイプではいくつかの制限がなくなり、プロセス全体が大幅に単純化されています。

クラス注釈(@PortableType)と属性注釈(@Portableおよび関連する注釈)の両方によって、クラスの進化に必要なバージョニング情報を指定する方法が提供されます。

クラス・レベルでは、新しい属性を導入してクラスを変更するたびに、@PortableType注釈のバージョン・プロパティを増分する必要があります。

同時に、新しいクラス属性の新しいクラス・バージョン番号と一致するsince属性を指定する必要があります。たとえば、age属性をPetクラスに追加し、color属性をDogクラスに追加するには、前述のコードを変更します(使用方法の基本の理解を参照)。
@PortableType(id = 1, version = 1)
public class Pet
    {
    @Portable
    protected String name;

    @Portable(since = 1)
    protected int age;

    // constructors, accessors, etc.
    }

@PortableType(id = 2, version = 1)
public class Dog extends Pet
    {
    @Portable
    private String breed;

    @Portable(since = 1)
    private Color color;

    // constructors, accessors, etc.
    }

versionプロパティとsinceプロパティの両方がゼロベースであるため、初期実装で完全に省略できます。また、後続の最初のリビジョンでは、1に設定する必要があることも意味します。

これらは単なるデフォルトです。初期実装の場合でも、必要に応じてクラスおよび属性バージョンを任意の値に明示的に設定できます。重要なのは、今後クラスに変更を加えるたびに、バージョンを増分し、sinceプロパティを最新バージョン番号に設定することのみです。

たとえば、将来、heightおよびweight属性をPetクラスに追加する場合は、version2に増分し、新しい属性のsinceプロパティをそれに応じて次のように設定する必要があります。
@PortableType(id = 1, version = 2)
public class Pet
    {
    @Portable
    protected String name;

    @Portable(since = 1)
    protected int age;

    @Portable(since = 2)
    protected int height;

    @Portable(since = 2)
    protected int weight;

    // constructors, accessors, etc.
    }

ノート:

クラスの進化では、新しいバージョンのクラスに属性を追加できますが、既存の属性を削除するとクラス・バージョン間のシリアライズが壊れるため、削除しないでください。

ただし、クラスから属性アクセッサを削除または非推奨にすることはできますが、シリアライズ形式の下位互換性を維持するために、フィールド自体はそのままにしておく必要があります。

同様に、フィールドのデフォルトのシリアライズ順序は、特定のクラス・バージョン内のフィールド名のアルファベット順(同じsince値を持つすべてのフィールド)に基づいて決定されるため、フィールドの名前は変更しないでください。

POFエクストラクタの使用

ポータブル・タイプを使用する場合、ValueExtractorsを作成するには、Extractors.fromPofファクトリ・メソッドを使用することをお薦めします。一般的な使用方法は次のとおりです。
Extractors.fromPof(rootClass, propertyPath)
Petクラスがあり、名前を抽出する場合は、次を使用できます。
ValueExtractor<Person, String> nameExtractor = Extractors.fromPof(Pet.class, "name");
Addressプロパティを持つPersonクラスがある場合は、次のようにネストされたcityプロパティのエクストラクタを作成できます。
ValueExtractor<Person, String> cityExtractor = Extractors.fromPof(Person.class, "address.city");

コンパイル時のクラスの計測

クラスへの注釈付けは、ポータブル・タイプの実装の最初のステップですが、それだけでは十分ではありません。必要なシリアライズ・ロジックを実装するには、コンパイル時にクラスも計測する必要があります。

インストゥルメンテーションには、次のオプションを使用できます:

Maven POFプラグインの使用
このタスクは、pof-maven-pluginプラグインを使用して完了できます。次に示すように、pom.xmlファイルでこのプラグインを構成する必要があります:
<plugin>
  <groupId>com.oracle.coherence.ce</groupId>
  <artifactId>pof-maven-plugin</artifactId>
  <version>22.06</version>
  <executions>
    <execution>
      <id>instrument</id>
      <goals>
        <goal>instrument</goal>
      </goals>
    </execution>
    <execution>
      <id>instrument-tests</id>
      <goals>
        <goal>instrument-tests</goal>
      </goals>
    </execution>
  </executions>
</plugin>

前述の構成では、テスト・クラスを含む、@PortableType注釈が付いたすべてのプロジェクト・クラスを検出して計測します。テスト・クラスを計測する必要がない場合は、instrument-testsの実行をプラグイン構成から省略できます。

pof-maven-pluginでは、Schemaサポートを使用して、アクセス可能なすべてのポータブル・タイプを含むタイプ・システムを定義します。このタイプのシステムには、計測する必要があるプロジェクト・クラスだけでなく、プロジェクトの依存関係に存在するすべてのポータブル・タイプも含まれます。これが必要なのは、これらの依存型がプロジェクト・クラス内の属性として使用される可能性があり、適切にシリアライズする必要があるためです。

場合によっては、 @PortableType注釈が付いておらず、自動的に検出されないタイプでタイプ・システムを拡張することが必要な場合があります。これは通常、一部のポータブル・タイプに列挙値があるか、PortableObjectインタフェースを属性として明示的に実装する既存のクラスがある場合に当てはまります。

これらのタイプをスキーマに追加するには、META-INF/schema.xmlファイルを作成し、明示的に指定します。たとえば、前述のコード例のColorクラス(クラスのバージョニングおよび進化を参照)が列挙型であると仮定した場合、次のMETA-INF/schema.xmlファイルを作成して登録し、pof-maven-pluginプラグインがDogクラスを正しく計測できるようにする必要があります。
<?xml version="1.0"?>

<schema xmlns="http://xmlns.oracle.com/coherence/schema"
       xmlns:java="http://xmlns.oracle.com/coherence/schema/java"
       external="true">

  <type name="Color">
    <java:type name="petstore.Color"/>
  </type>

</schema>
これらの部分がすべて配置されたら、通常通りビルドを実行するだけです。
$ mvn clean install
Maven出力ログをチェックすることで、クラスが正常に計測されているかどうかを確認できます。次のようなマップが表示されます。
[INFO] --- pof-maven-plugin:21.12:instrument (instrument) @ petstore ---
[INFO] Running PortableTypeGenerator for classes in /projects/petstore/target/classes
[INFO] Instrumenting type petstore.Pet
[INFO] Instrumenting type petstore.Dog

クラスの計測が正常に完了すると、クラスを登録して使用する準備が整います。

Gradle POFプラグインの使用

POF Gradleプラグインは、@PortableType注釈を使用してクラスの自動インストゥルメンテーションを提供し、Evolvable POFシリアライズ・メソッドの一貫した(および正しい)実装を生成します。

Evolvableの概念をサポートする継承階層のシリアライズをサポートするシリアライズ・メソッドを手動で記述することは簡単なことではありません。しかし、静的型解析を使用すると、これらのメソッドを決定論的に生成できます。

メソッドを決定論的に生成すると、開発者は、Evolvable POFシリアライズ・メソッドのボイラープレート・コードの実装ではなく、ビジネス・ロジックに集中できます。ポータブル・タイプの詳細は、「ポータブル・タイプについて」を参照してください。

POF Gradleプラグインを使用するには、build.gradleファイルでプラグイン依存関係として宣言する必要があります:

plugins {
    id 'java'
    id 'com.oracle.coherence.ce' version '23.03'
    }

ノート:

オープン・ソースのGradle POFプラグインのみがCoherence 14.1.1.2206で動作します。

これ以上の構成をしなくても、プラグインはcoherencePofという名前のタスクをプロジェクトに追加します。coherencePofタスクは、compileJavaタスクの終了時に実行されます。同時に、coherencePofcompileJavaタスクに依存します。

したがって、gradle compileJavaをコールすると、coherencePofタスクが実行されます。同様に、gradle coherencePofをコールすると、最初にcompileJavaタスクが実行されます。デフォルトでは、coherencePofタスクは、ビルド出力ディレクトリを、インストゥルメントされるクラス(テスト・クラスを除く)の入力とみなします。

プラグインを依存関係として追加するだけで、POF Gradleプラグインは、テスト・クラスを除く@PortableType注釈が付いたすべてのプロジェクト・クラスを検出してインストゥルメントします。テスト・クラスをインストゥルメントする必要がある場合は、coherencePofクロージャを追加して、追加の構成プロパティを指定できます。

この項には次のトピックが含まれます:

Gradle構成のカスタマイズ
Coherence Gradleプラグインのデフォルトの動作は、いくつかのオプション・プロパティを使用してカスタマイズできます。次の例に示すように、追加の構成プロパティを含むbuild.gradleスクリプトにcoherencePofクロージャを指定するのみです:
coherencePof {
  debug=true 
}

この例では、debug=trueによって、インストゥルメントされたクラスのロギング出力を増やすようにCoherenceに指示します。

使用可能な構成プロパティ
使用可能な構成プロパティは次のとおりです:
  • デバッグの有効化: ブールdebugプロパティをtrueに設定して、インストゥルメントされたクラスのデバッグ・コードを生成するように基礎となるPortableTypeGeneratorに指示します。指定しない場合、このプロパティはデフォルトでfalseになります。
  • テスト・クラスのインストゥルメンテーション: テスト・クラスをインストゥルメントするには、ブールinstrumentTestClassesプロパティをtrueに設定します。指定しない場合、このプロパティはデフォルトでfalseになります。
  • カスタムTestClassesDirectoryの設定: testClassesDirectoryプロパティを使用して、カスタム・テスト・クラス・ディレクトリへのパスを指定します。設定しない場合、デフォルトのテスト出力ディレクトリにデフォルト設定されます。
  • カスタムMainClassesDirectoryの設定: mainClassesDirectoryプロパティを使用して、カスタム・クラス・ディレクトリへのパスを指定します。設定しない場合、デフォルトの出力ディレクトリにデフォルト設定されます。
@PortableType注釈のないクラスの使用

場合によっては、@PortableType注釈が付いておらず、自動的に検出されないタイプでタイプ・システムを拡張することが必要な場合があります。これは通常、一部のポータブル・タイプにenum値があるか、PortableObjectインタフェースを属性として明示的に実装する既存のクラスがある場合です。

これらのタイプをスキーマに追加するには、META-INF/schema.xmlファイルを作成し、明示的に指定します。たとえば、Colorクラスを使用している場合:
<?xml version="1.0"?>

<schema xmlns="http://xmlns.oracle.com/coherence/schema"
        xmlns:java="http://xmlns.oracle.com/coherence/schema/java" external="true">

  <type name="Color">
    <java:type name="petstore.Color"/>
  </type>
</schema>
Jandex Gradleプラグインの追加

Coherenceのポータブル・タイプの検出機能は、登録する必要があるポータブル・タイプを提供するモジュール内のJandex索引の可用性によって異なります。

そのため、Gradleプロジェクトでコンパイル時にPOFインストゥルメント・クラスを使用するには、Jandex Gradleプラグインも追加する必要があります。Oracle Coherenceは内部でJandex 2を使用するため、次の2つのオプションがあります:

  • チェックサム依存関係プラグイン
    plugins {
      id 'java'
      id 'com.oracle.coherence.ce' version '23.03'
      id 'com.github.vlsi.jandex' version '1.86'
    }
  • jandex-gradle-plugin(最新バージョンではJandex 3を使用するため、バージョン< 1.0.0に対してのみ)。
    plugins {
      id 'java'
      id 'com.oracle.coherence.ce' version '23.03'
      id 'org.kordamp.gradle.jandex' version '0.13.2'
    }
プラグインを使用したPersonクラスの処理 - 例

Personクラスの例(ソース・コードを次に示します)をプラグインで処理すると、次の出力に示すようなバイトコードが生成されます:

例27-1 プラグインを使用したPersonクラスの処理

@PortableType(id=1000)
public class Person
    {
    public Person()
        {
        }

    public Person(int id, String name, Address address)
        {
        super();
        this.id = id;
        this.name = name;
        this.address = address;
        }

    int id;
    String name;
    Address address;

    // getters and setters omitted for brevity
    }
生成されたバイトコードを調べます:
javap Person.class

これによって、次が出力されます:

public class demo.Person implements com.tangosol.io.pof.PortableObject,com.tangosol.io.pof.EvolvableObject {
  int id;
  java.lang.String name;
  demo.Address address;
  public demo.Person();
  public demo.Person(int, java.lang.String, demo.Address);
  public int getId();
  public void setId(int);
  public java.lang.String getName();
  public void setName(java.lang.String);
  public demo.Address getAddress();
  public void setAddress(demo.Address);
  public java.lang.String toString();
  public int hashCode();
  public boolean equals(java.lang.Object);

  public void readExternal(com.tangosol.io.pof.PofReader) throws java.io.IOException; 
  public void writeExternal(com.tangosol.io.pof.PofWriter) throws java.io.IOException;
  public com.tangosol.io.Evolvable getEvolvable(int);
  public com.tangosol.io.pof.EvolvableHolder getEvolvableHolder();
}

出力の最後の部分は、Coherence POFプラグインによって生成された追加のメソッドを示しています。

タスクの実行のスキップ
次の例に示すように、-xフラグを使用してGradleビルドを実行することで、coherencePofタスクの実行をスキップできます:
gradle clean build -x coherencePof
開発中のプラグイン・コードのテスト
開発時には、個別のサンプル・プロジェクトに対してプラグイン・コードを迅速にテストすることが非常に有用です。これには、Gradleの複合ビルド機能を使用できます。『Composing builds』を参照してください。したがって、Coherence POF Gradleプラグイン・モジュール自体は、個別のサンプル・モジュールを提供します。サンプル・ディレクトリ内から、次のコマンドを実行します:
gradle clean compileJava --include-build ../plugin

このコマンドは、サンプルをビルドするだけでなく、プラグインもビルドします。そのため、開発者はプラグイン・コードを変更し、その変更がサンプル・モジュールの実行で迅速に反映されることを確認できます。

または、次のコマンドを使用して、Coherence Gradleプラグインをビルドし、ローカルMavenリポジトリにインストールできます:
gradle publishToMavenLocal

プロジェクトでローカル変更を取得するには、次の構成を確認してください:

  • Build.gradle
    plugins {
      id 'java'
      id 'com.oracle.coherence.ce' version '23.03'
      id 'com.github.vlsi.jandex' version '1.86'
    }
  • Settings.gradle
    pluginManagement {
      repositories {
        mavenLocal()
        gradlePluginPortal()
      }
    }

登録および検出

Portable Object Formatは自己記述型のシリアライズ形式ではありません。プラットフォーム固有のクラス名を整数ベースのタイプ識別子で置き換えます。そのため、これらのタイプ識別子をプラットフォーム固有のクラスにマップして戻す方法が必要です。このマッピングにより、POFの主な目的であるプラットフォーム間の移植性が得られます。

タイプ識別子と具体的なタイプ間のマッピングを管理するために、POFではcom.tangosol.io.pof.PofContextを使用します。
public interface PofContext extends Serializer
    {
    PofSerializer getPofSerializer(int nTypeId);

    int getUserTypeIdentifier(Object o);
    int getUserTypeIdentifier(Class<?> clz);
    int getUserTypeIdentifier(String sClass);

    String getClassName(int nTypeId);
    Class<?> getClass(int nTypeId);

    boolean isUserType(Object o);
    boolean isUserType(Class<?> clz);
    boolean isUserType(String sClass);
    }

PofContextは、com.tangosol.io.Serializerインタフェースを拡張することに注意してください。つまり、CoherenceがSerializerを指定する必要がある場合、つまり、キャッシュ・サービス内でデータ・クラスのストレージ・レベルのシリアライザとして、シン・クライアントとプロキシ・サーバー間のトランスポート・レベルのシリアライザとしてなど、すべてのPofContext実装を使用できます。PofContextは、タイプ識別子に基づいてPofContext.getPofSerializerメソッドから取得される適切なPofSerializerに委任することで、実際のシリアライズを実行します。

PofContextには、いくつかの組込み実装があります。SimplePofContextを使用すると、シリアライズに必要なすべてのメタデータ(タイプ識別子、クラス、使用するPofSerializerなど)を指定して、タイプ・マッピングをプログラムで登録できます。
SimplePofContext ctx = new SimplePofContext();
ctx.registerUserType(1, Pet.class, new PortableTypeSerializer<>(1, Pet.class));
ctx.registerUserType(2, Dog.class, new PortableTypeSerializer<>(2, Dog.class));
ctx.registerUserType(3, Color.class, new EnumPofSerializer());

必要なすべてのメタデータはクラス自体または@PortableType注釈から取得できるため、ポータブル・タイプを操作する際には、この情報の多くはやや繰返しであり、不要です。

SimplePofContextには、特にポータブル・タイプ用の便利なメソッドもいくつか用意されています。
ctx.registerPortableType(Pet.class);
ctx.registerPortableType(Dog.class);
よりシンプルにすると:
ctx.registerPortableTypes(Pet.class, Dog.class);

SimplePofContextはテストおよび迅速なプロトタイピングに役立ちますが、Coherenceアプリケーション内でより広く使用されているPofContext実装はConfigurablePofContextです。

ConfigurablePofContextでは、外部XMLファイルを介してタイプ・マッピングを指定できます:
<pof-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
              xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config coherence-pof-config.xsd">

  <user-type-list>

    <user-type>
      <type-id>1</type-id>
      <class-name>petstore.Pet</class-name>
    </user-type>

    <user-type>
      <type-id>2</type-id>
      <class-name>petstore.Dog</class-name>
    </user-type>

    <user-type>
      <type-id>3</type-id>
      <class-name>petstore.Color</class-name>
      <serializer>
        <class-name>com.tangosol.io.pof.EnumPofSerializer</class-name>
      </serializer>
    </user-type>

  </user-type-list>

</pof-config>

PetおよびDogクラスのシリアライザを明示的に指定していないことに注意してください。これは、ConfigurablePofContextには、実装されているインタフェースまたは指定したクラスに存在する注釈に応じて、使用する組込みのPofSerializer実装を決定するロジックがあるためです。この場合、クラスには@PortableType注釈があるため、PortableTypeSerializerが自動的に使用されます。

ただし、ポータブル・タイプの検出を有効にすることで、構成をさらに単純化できます。
<pof-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
              xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config coherence-pof-config.xsd">

  <user-type-list>

    <user-type>
      <type-id>3</type-id>
      <class-name>petstore.Color</class-name>
      <serializer>
        <class-name>com.tangosol.io.pof.EnumPofSerializer</class-name>
      </serializer>
    </user-type>

  </user-type-list>

  <enable-type-discovery>true</enable-type-discovery>

</pof-config>
enable-type-discoveryフラグをtrueに設定すると、ConfigurablePofContextは、@PortableType注釈が付いたすべてのクラスを検出し、注釈メタデータに基づいて自動的に登録します。明示的に登録する必要があるColor列挙を使用しない場合は、構成ファイルを完全に省略することもできます。Coherenceに組み込まれているデフォルトのpof-config.xmlファイルは次のようになります。
<pof-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
              xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config coherence-pof-config.xsd">

  <user-type-list>
    <!-- by default just include coherence POF user types -->
    <include>coherence-pof-config.xml</include>
  </user-type-list>

  <enable-type-discovery>true</enable-type-discovery>

</pof-config>

ノート:

ポータブル・タイプの検出機能は、登録する必要があるポータブル・タイプを提供するモジュール内のJandex索引の可用性によって異なります。

ビルド時にモジュール内のクラスに索引付けするように、Jandex Mavenプラグインを構成してください。
<plugin>
  <groupId>org.jboss.jandex</groupId>
  <artifactId>jandex-maven-plugin</artifactId>
  <version>1.0.8</version>
  <executions>
    <execution>
      <id>make-index</id>
      <goals>
        <goal>jandex</goal>
      </goals>
      <phase>process-classes</phase>
    </execution>
  </executions>
</plugin>

IDEサポートの提供

クラスのバージョニングおよび進化コンパイル時のクラスの計測および登録および検出の説明に従って、ポータブル・タイプに注釈を付け、計測および登録した後は、デフォルトのjavaシリアライザのかわりにpofシリアライザを使用するようにCoherenceサービスを構成することで、プレーンなJava Serializableクラスを使用する場合と同じくらい簡単にポータブル・タイプをCoherenceで使用できます。

しかし、まだ1つの問題があります。シリアライズ・コードは、コンパイル時にpof-maven-pluginプラグインによって実装され、Mavenビルドを実行した場合にのみ実装されます。これにより、統合開発環境(IDE)内でユニットおよび統合テストを実行することが少し難しくなることがあります。

この問題を解決するために、OracleはIntelliJ IDEAおよびEclipse用のIDEプラグインを実装しました。これらのプラグインは、IDEによって実行される増分コンパイルまたは完全コンパイル中にクラスを計測できます。これにより、Mavenビルドを実行したりIDEから離脱することなく、クラスのシリアライズとそれに依存するコードの両方をテストできます。

お気に入りのIDEのプラグインをインストールして使用するための詳細な手順は、次のプラグインのドキュメントを参照してください。

詳細POFシリアライズ・オプションの使用

POFオブジェクトをシリアライズするには、ポータブル・タイプをお薦めします。この項では、com.tangosol.io.pof.PofSerializerインタフェースの使用に関連する様々な詳細シリアライズ・オプションについて説明します。

この項には次のトピックが含まれます:

PofSerializerインタフェースの実装

PofSerializerインタフェースには、シリアライズ・ロジックをシリアライズするクラスから外部化する手段が用意されています。これは、CoherenceでPOFを使用する場合に、クラスの構造を変更したくないときには特に役立ちます。PofSerializerインタフェースは、次の2つのメソッドで構成されています。

  • public Object deserialize(PofReader in)

  • public void serialize(PofWriter out, Object o)

PortableObjectインタフェース同様、POFストリームに対して書込みまたは読取りが実行される要素はすべて一意に索引付けされている必要があります。PofSerializerインタフェースの実装例を、次に示します。

public Object deserialize(PofReader in) 
   throws IOException 
   {
   Symbol symbol    = (Symbol)in.readObject(0);
   long   ldtPlaced = in.readLong(1);
   bool   fClosed   = in.readBoolean(2);
   
   // mark that reading the object is done
   in.readRemainder();
 
   return new Trade(symbol, ldtPlaced, fClosed);
   }
 
public void serialize(PofWriter out, Object o) 
   throws IOException 
   {
   Trade trade = (Trade) o;
   out.writeObject(0, trade.getSymbol());
   out.writeLong(1, trade.getTimePlaced());
   out.writeBoolean(2, trade.isClosed());
    
   // mark that writing the object is done
   out.writeRemainder(null);
   }

Evolvableインタフェースの実装

Evolvableインタフェースを実装する際には、新しいバージョンのクラスで新しい要素の追加を処理するように注意する必要があります。新しいクラスでは、古いバージョンのクラスを読み取るときにデータの誤った処理を防ぐため、新しい要素を読み取らないように保護する必要があります。

たとえば、PortableObjectを実装する場合:
public void readExternal(PofReader in)
   throws IOException
   {
   m_symbol    = (Symbol) in.readObject(0);
   m_ldtPlaced = in.readLong(1);
   m_fClosed   = in.readBoolean(2);
  
   if (in.getVersionId() >= 2)
       {
       m_lShares = in.readInt(3);
       }
   }
または、PofSerializerを実装する場合:
public Object deserialize(PofReader in)
   throws IOException
   {
   Symbol symbol    = (Symbol)in.readObject(0);
   long   ldtPlaced = in.readLong(1);
   bool   fClosed   = in.readBoolean(2);

   if (in.getVersionId() >= 2)
       {
       lShares = in.readInt(3);
       }
  
   // mark that reading the object is done
   in.readRemainder();
 
   if (in.getVersionId() >= 2)
       {
       return new Trade(symbol, ldtPlaced, fClosed, lShares);
       }
   else
       {
       return new Trade(symbol, ldtPlaced, fClosed);
       }
   }

読取り時にチェックが行われるため、書込みまたはシリアライズでは、これらのチェックを行う必要はありません。

POF索引の割当てのガイドライン

ノート:

プロパティ索引管理は内部的に処理されるため、ポータブル・タイプを使用している場合、これらのガイドラインは関係ありません。

POFの索引をオブジェクトの属性に割り当てるときには、次のガイドラインに従ってください。

  • 読取りと書込みの順序: シリアライズ・ルーチンの最低索引値から開始して、最高索引値で終了します。値をデシリアライズする場合には、書込みと同じ順序で読取りを実行します。

  • 非連続の索引を指定することはできますが、読取りまたは書込みが連続して実行される必要があります。

  • サブクラス作成時に索引の範囲を予約する場合: 索引は派生タイプ間で累積されます。そのため、各派生タイプがそのスーパークラスで予約されたPOF索引範囲を認識する必要があります。

  • 索引を他の目的に使用しない: 進化をサポートするためには、クラス・リビジョン全体で属性の索引を他の目的に使用しないようにすることが必須です。

  • ラベルの索引: public static final intでラベル付けされている索引は、さらに簡単に使用できます。特に、POFエクストラクタとPOFアップデータを使用する場合には簡単です。POFエクストラクタとPOFアップデータの使用を参照してください。ラベル付けされた索引の読取りおよび書込みも、上述の説明と同じ順序で実行される必要があります。

POFオブジェクト参照の使用

この項には次のトピックが含まれます:

POFオブジェクト参照の概要

POFでは、POFストリーム内で複数回出現するオブジェクトに、オブジェクトのIDや参照の使用がサポートされています。オブジェクトには、IDが付けられ、同じPOFストリーム内で2回目以降に出現するラベルが付いたオブジェクトは、そのIDで参照されます。

参照を使用することで、同じオブジェクトを複数回エンコーディングすることを防ぎ、データサイズを削減できます。一般に、参照を使用するのは、サイズの大きな多数のオブジェクトが複数回生成されるときや、オブジェクトでネストや循環データ構造が使用されるときです。ただし、大量のデータがあり、繰返しが少ないアプリケーションの場合、オブジェクト参照を使用してもオブジェクトのIDや参照の追跡によって生じるオーバーヘッドのために、最小限の利点しかありません。

オブジェクト・アイデンティティおよび参照の使用には次の制限があります。

  • オブジェクト参照には、ユーザー定義のオブジェクト型のみがサポートされています。

  • Evolvableオブジェクトでは、オブジェクト参照はサポートされていません。

  • キーでは、オブジェクト参照はサポートされていません。

  • 参照をサポートしていないPOFコンテキストによって記述されたオブジェクトは、参照をサポートするPOFコンテキストで読み込むことができません。また、この逆の場合も同様です。

  • POFエクストラクタを使用して、オブジェクト・アイデンティティおよび参照を使用するPOFオブジェクトを問い合せることはできません。かわりに、ValueExtractor APIを使用してオブジェクト値を問い合せるか、またはオブジェクト参照を無効にしてください。

  • PofNavigatorおよびPofValue APIには、オブジェクト参照を使用する際に次の制限があります:

    • 読取り操作のみ許可されます。書込み操作はUnsupportedOperationExceptionとなります。

    • ユーザー・オブジェクトは非共通コレクションでアクセスできますが、共通コレクションではアクセスできません。

    • 読取り操作については、オブジェクトがデータ・ストリームで複数回出現する場合、オブジェクトが最初に出現した場所で読み取られてから、次のデータの部分で読み取られる必要があります。そうでない場合は、IOException: missing identity: <ID>がスローされます。たとえば、リストが3つあり、そのすべてが同じPersonオブジェクトpを含む場合。pオブジェクトは、最初のリストで読み取られてから2番目または3番目のリストで読み取られる必要があります。

POFオブジェクト参照の有効化

オブジェクト参照は、デフォルトでは無効になっており、SimplePofContextクラスを使用するときにpof-config.xml構成ファイル内か、プログラムによって有効にする必要があります。

POF構成ファイルでオブジェクト参照を有効にするには、<pof-config>要素内に<enable-references>要素を含めて、値をtrueに設定します。たとえば:

<?xml version='1.0'?>

<pof-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
   xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config
   coherence-pof-config.xsd">
   ...
   <enable-references>true</enable-references>
</pof-config>

SimplePofContextクラスの使用時にオブジェクト参照を有効にするには、プロパティをtrueに設定してsetReferenceEnabledメソッドをコールします。たとえば:

SimplePofContext ctx = new SimplePofContext();
ctx.setReferenceEnabled(true);
循環構造のオブジェクトやネストされたオブジェクトへのPOFオブジェクトIDの登録

循環構造のオブジェクトやネストされたオブジェクトは、オブジェクトの作成時に手動でIDを登録する必要があります。そうしないと、親オブジェクトを参照する子オブジェクトは、参照マップ内で親のIDを見つけることができません。オブジェクトIDは、com.tangosol.io.pof.PofReader.registerIdentityメソッドを使用して、デシリアライズ・ルーチン中にシリアライザから登録できます。

次の例では、循環参照を含んだ2つのオブジェクト(CustomerおよびProduct)と、CustomerオブジェクトのIDを登録するシリアライザ実装を示しています。

Customerオブジェクトの定義は次のとおりです。

public class Customer
   {
   private String m_sName;
   private Product m_product;
 
   public Customer(String sName)
      {
      m_sName = sName;
      }
 
   public Customer(String sName, Product product)
      {
      m_sName = sName;
      m_product = product;
      }

   public String getName()
      {
      return m_sName;
      }

   public Product getProduct()
      {
      return m_product;
      }
 
   public void setProduct(Product product)
      {
      m_product = product;
      }
   }

Productオブジェクトの定義は次のとおりです。

public class Product
   {
   private Customer m_customer;
 
   public Product(Customer customer)
      {
      m_customer = customer;
      }
 
   public Customer getCustomer()
      {
      return m_customer;
      }
   }

デシリアライズの間にIDを登録するシリアライザ実装の定義は次のとおりです。

public class CustomerSerializer implements PofSerializer
   {
   @Override
   public void serialize(PofWriter pofWriter, Object o) throws IOException
      {
      Customer customer = (Customer) o;
      pofWriter.writeString(0, customer.getName());
      pofWriter.writeObject(1, customer.getProduct());
      pofWriter.writeRemainder(null);
      }
 
   @Override
   public Object deserialize(PofReader pofReader) throws IOException
      {
      String sName = pofReader.readString(0);
      Customer customer = new Customer(sName);

      pofReader.registerIdentity(customer);
      customer.setProduct((Product) pofReader.readObject(1));
      pofReader.readRemainder();
      return customer;
      }
   }

POFオブジェクトの登録

Coherenceには、com.tangosol.io.pof.ConfigurablePofContextシリアライザ・クラスが用意されていて、それによりPOFのシリアライズ・オブジェクトが適切なシリアライズ・ルーチン(PofSerializer実装、またはPortableObjectインタフェースを介した呼び出しによる)にマップされます。

クラスにシリアライズ・ルーチンが指定されると、そのクラスはpof-config.xml構成ファイルを使用してConfigurablePofContextクラスに登録されます。POF構成ファイルには<user-type-list>要素があり、それにはPortableObjectを実装するクラスまたはそれらに関連付けられているPofSerializerを持つクラスのリストが記載されています。各クラスに対する<type-id>は一意である必要があり、すべてのクラスタ・インスタンス(拡張クライアントを含む)で一致している必要があります。POFユーザー定義型の構成要素を参照してください。

POF構成ファイルの例を次に示します。

<?xml version='1.0'?>

<pof-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
   xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config
   coherence-pof-config.xsd">
   <user-type-list>
      <include>coherence-pof-config.xml</include>

      <!-- User types must be above 1000 -->
      <user-type>
         <type-id>1001</type-id>
         <class-name>com.examples.MyTrade</class-name>
         <serializer>
            <class-name>com.examples.MyTradeSerializer</class-name>
         </serializer>
      </user-type>
 
      <user-type>
        <type-id>1002</type-id>
        <class-name>com.examples.MyPortableTrade</class-name>
      </user-type>
   </user-type-list>
</pof-config>

ノート:

Coherenceでは、最初の1000個のtype-idは内部使用のために予約されています。上の例に示されているように、<user-type-list>にはcoherence.jarファイルのルートにあるcoherence-pof-config.xmlファイルが含まれます。このリストにはCoherence固有のユーザー型が定義されており、それらのユーザー型はすべてのPOF構成ファイルに含まれている必要があります。

ConfigurablePofContextクラスを使用するためのCoherenceの構成

この項には次のトピックが含まれます:

ConfigurablePofContextクラスの使用の概要

CoherenceでConfigurablePofContextシリアライザ・クラスを使用する場合には、必要な精度のレベルに基づいた、次の3通りの構成が可能です。

  • サービスごと - 各サービスには、ConfigurablePofContextシリアライザ・クラスの完全な構成が用意されており、オペレーション構成ファイルにある事前定義済の構成が参照されます。

  • すべてのサービス - すべてのサービスでグローバルConfigurablePofContextシリアライザ・クラスの構成が使用されます。独自の構成を提供するサービスによってグローバルな構成がオーバーライドされます。グローバル構成を完全構成にして、オペレーション構成ファイルに含まれる事前定義済の構成を参照することも可能です。

  • JVM - ConfigurablePofContextシリアライザ・クラスはJVM全体に対して有効化されます。

ConfigurablePofContextクラスのサービスごとの構成

ConfigurablePofContextクラスを使用するようにサービスを構成するには、キャッシュ構成ファイルのキャッシュ・スキームに<serializer>要素を追加します。serializerを参照してください。

次の例では、ConfigurablePofContextクラスを使用するように構成された分散キャッシュを示しており、カスタムPOF構成ファイルを定義しています。

 <distributed-scheme>
   <scheme-name>example-distributed</scheme-name>
   <service-name>DistributedCache</service-name>
   <serializer>
      <instance>
         <class-name>com.tangosol.io.pof.ConfigurablePofContext</class-name>
         <init-params>
            <init-param>
               <param-type>String</param-type>
               <param-value>my-pof-config.xml</param-value>
            </init-param>
         </init-params>
      </instance>
   </serializer>
</distributed-scheme>

次の例では、オペレーション構成ファイルのデフォルトの定義を参照します。serializerを参照してください。

 <distributed-scheme>
    <scheme-name>example-distributed</scheme-name>
    <service-name>DistributedCache</service-name>
    <serializer>pof</serializer>
 </distributed-scheme>
すべてのサービスに対するConfigurablePofContextクラスの構成

ConfigurablePofContextクラスをすべてのサービスに対してグローバルに構成するには、キャッシュ構成ファイルの<defaults>要素内に<serializer>要素を追加します。次の例は両方とも、シリアライザをすべてのキャッシュ・スキームの定義に対してグローバルに構成するものであり、個々のキャッシュ・スキームの定義内にその他の構成を追加する必要はありません。defaultsを参照してください。

次の例では、ConfigurablePofContextクラスに対するグローバルな構成を示しており、カスタムPOF構成ファイルを定義しています。

<?xml version='1.0'?>

<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
   xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config
   coherence-cache-config.xsd">
   <defaults>
      <serializer>
         <instance>
            <class-name>com.tangosol.io.pof.ConfigurablePofContext</class-name>
            <init-params>
               <init-param>
                  <param-type>String</param-type>
                  <param-value>my-pof-config.xml</param-value>
               </init-param>
            </init-params>
         </instance>
      </serializer>
   </defaults>
   ...

次の例では、オペレーション構成ファイルのデフォルトの定義を参照します。serializerを参照してください。

<?xml version='1.0'?>

<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
   xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config
   coherence-cache-config.xsd">
   <defaults>
      <serializer>pof</serializer>
   </defaults>
   ...
JVMインスタンスに対するConfigurablePofContextクラスの構成

次のシステム・プロパティを使用して、POFを使用するようにJVMインスタンス全体を構成できます。

  • coherence.pof.enabled=true - JVMインスタンス全体でPOFを有効化します。

  • coherence.pof.config=CONFIG_FILE_PATH - 使用するPOF構成ファイルへのパスです。このファイルがクラスパスにない場合には、ファイル・リソースとして存在するはずです(たとえば、file:///opt/home/coherence/mycustom-pof-config.xml)。

実行時にPOF構成ファイルを検出可能にする

デプロイ時または実行時に新しいモジュールが追加される可能性があるJavaアプリケーションでは、必要なPOF構成ファイルの完全なセットが事前にわからない場合があります。そのため、すべての正しい<include>要素を含むPOF構成ファイルを作成できない場合があります。このタイプのユース・ケースを可能にするために、POF構成ファイルをConfigurablePofContextクラスによって実行時に検出可能にすることができ、<include>要素内に配置する必要はありません。

構成ファイルを検出可能にするには、com.tangosol.io.pof.PofConfigProviderを実装するクラスを作成します。PofConfigProviderには、構成ファイルの名前を返すために実装する必要がある単一のメソッドがあります。実行時に、ConfigurablePofContextクラスはJava ServiceLoaderを使用してPofConfigProviderの実装を検出し、指定されたPOF構成ファイルを、<include>要素に追加されたかのように正確にロードします。

たとえば、次のRuntimeConfigProviderクラスは、構成ファイル名としてdiscovered-pof-config.xmlを指定しています。実行時に、ConfigurablePofContextクラスはdiscovered-pof-config.xml POF構成ファイルをロードします。

RuntimeConfigProvider.java

package com.oracle.coherence.examples;

import com.tangosol.io.pof.PofConfigProvider;

public class RuntimeConfigProvider
        implements PofConfigProvider
    {
    @Override
    public String getConfigURI()
        {
        return "discovered-pof-config.xml";
        }
    }
RuntimeConfigProviderクラスを検出可能にするには:
  • 次を含むファイルMETA-INF/services/com.tangosol.io.pof.PofConfigProviderを作成します。
    com.oracle.coherence.examples.RuntimeConfigProvider
  • Javaモジュールを使用する場合は、module-info.javaファイルに追加します。
    module com.oracle.coherence.examples {
        provides com.tangosol.io.pof.PofConfigProvider
            with com.oracle.coherence.examples.RuntimeConfigProvider;
    }

必要に応じて、PofConfigProvider実装は、PofConfigProvider.getConfigURIs()メソッドをオーバーライドすることによって、複数のPOF構成ファイルを返すことができます。この場合、単一のgetConfigURI()はコールされません。

次の例では、RuntimeConfigProvidergetConfigURIs()メソッドは、POF構成ファイル名discovered-pof-config.xmlおよびadditional-pof-config.xmlを返します。これらは両方とも実行時にConfigurablePofContextによってロードされます。
package com.oracle.coherence.examples;

import com.tangosol.io.pof.PofConfigProvider;

import java.util.Set;

public class RuntimeConfigProvider
        implements PofConfigProvider
    {
    @Override
    public Set<String> getConfigURIs()
        {
        return Set.of("discovered-pof-config.xml",
                "additional-pof-config.xml");
        }

    @Override
    public String getConfigURI()
        {
        return null;
        }
    }

POFエクストラクタとPOFアップデータの使用

Coherenceでは、ValueExtractorインスタンスとValueUpdaterインスタンスを使用して、キャッシュに格納されたオブジェクトの値が抽出および更新されます。

PofExtractorおよびPofUpdaterインタフェースは、POFの索引付けされた状態を利用して、シリアライズ・ルーチンまたはデシリアライズ・ルーチン全体を実行せずに値を抽出または更新します。

PofExtractorPofUpdaterにより、Coherenceの非プリミティブ・タイプを使用するときの柔軟性が向上します。多くの拡張クライアントの場合、グリッド内に対応するJavaクラスは不要です。POFエクストラクタとPOFアップデータはバイナリをナビゲートできるため、キーと値全体をオブジェクト形式にデシリアライズしなくても済みます。これは、索引付けする値をPOFエクストラクタを使用してプルするだけで索引付けできることを意味します。ただし、キャッシュ・ストアを使用している場合は、対応するJavaクラスが必要です。この場合、キーと値のデシリアライズ・バージョンがキャッシュ・ストアに渡され、バックエンドに書き込まれます。

この項には次のトピックが含まれます:

POFエクストラクタの使用

POFエクストラクタは通常、キャッシュに問い合せる場合に使用され、問合せのパフォーマンスを向上させます。たとえば、上記で示したクラスを使用して、姓がJonesであるすべての連絡先のキャッシュに問い合せる場合、問合せは次のとおりです。

ValueExtractor veName = new PofExtractor(String.class, Contact.LASTNAME);
Filter         filter = new EqualsFilter(veName, "Jones");
 
// find all entries that have a last name of Jones
Set setEntries = cache.entrySet(filter);

この例では、PofExtractorには便利なコンストラクタがあり、SimplePofPathを使用して1つの索引(この例ではContact.LASTNAMEの索引)を取得します。地域コードが01803であるすべての連絡先を検索する場合、問合せは次のとおりです。

ValueExtractor veZip = new PofExtractor(
   String.class, new SimplePofPath(new int[] {Contact.WORK_ADDRESS, Address.ZIP}));
 
Filter filter = new EqualsFilter(veZip, "01803");
 
// find all entries that have a work address in the 01803 zip code
Set setEntries  = cache.entrySet(filter);

前述の例では、PofExtractorコンストラクタには抽出された値またはnullのクラスを持つ最初の引数があります。型情報を渡すのは、POFがシリアライズされた値で圧縮形式を使用するからです(使用可能な場合)。たとえば、一部の数値は、型が値を暗示する特殊なPOF固有型として示されています。その結果、POFの値を受け取る側では、その型を暗黙的に認識できることが必要になります。PofExtractorは、コンストラクタで提供されたクラスを型情報のソースとして使用します。このクラスがnullの場合、PofExtractorはシリアライズされた状態から型を推測しますが、抽出される型は予想した型と異なることがあります。実際には、String型はPOFストリームから適切に推測されるので、前述の例ではnullを使用すれば十分です。ただし、通常はnullを使用しないでください。

POFアップデータの使用

POFアップデータは、オブジェクトの値を抽出するのではなく、更新するという点を除いて、POFエクストラクタと同じ方法で動作します。姓がJonesであるすべてのエントリをSmithに変更するには、次のようにUpdaterProcessorクラスを使用します。

ValueExtractor veName  = new PofExtractor(String.class, Contact.LASTNAME);
Filter         filter  = new EqualsFilter(veName, "Jones");
ValueUpdater   updater = new PofUpdater(Contact.LASTNAME);

// find all Contacts with the last name Jones and change them to have the last
// name "Smith"

cache.invokeAll(filter, new UpdaterProcessor(updater, "Smith"));

ノート:

この機能は、これらの例ではStringベースの値で動作していますが、POFのエンコードされた値でも動作します。

POFを使用したキーのシリアライズ

値オブジェクトなどのキー・オブジェクトは、POFを使用してシリアライズできます。ただし、キーのシリアライズ時に考慮すべき点がいくつかあります。
  • POFではクロス・プラットフォームのオブジェクト形式を定義しますが、必ずしも対称的な変換を提供できるわけではありません。すなわち、シリアライズ・オブジェクトをデシリアライズすると、オブジェクトの型は元の型と異なる場合があります。これは、Javaの一部のデータ型は、.NETおよびC++プラットフォームに相当するものが存在しないために発生します。結果として、非対称のPOF変換を持つ可能性があるクラスは、キャッシュおよび他のJavaコレクションのキー(またはキーの一部)として使用しないでください。

  • java.util.Date型は使用しないようにしてください。POFは、(java.util.Dateを拡張した)java.sql.Timestampにシリアライズするように設計されています。それらの2つのクラスのワイヤ・フォーマットは同一であり、それらのワイヤ表現をデシリアライズすると、必ずjava.sql.Timestampインスタンスになります。残念ながら、それらの2つのベース・クラスのequalsメソッドでは、Javaコレクションのキーの対称要件は破壊されます。つまり、D (java.util.Date)とT (java.sql.Timestamp)という2つのオブジェクトがあり、これらのオブジェクトがPOFワイヤ・フォーマットの観点から等しい場合に、D.equals(T)はtrueになりますが、T.equals(D)はfalseになります。そのため、java.util.Dateは使用しないでください。キーの対称要件を破壊しないようにするには、日付のLong表現かjava.sql.Timestamp型を使用します。

  • POFオブジェクト参照を使用しているキーはシリアライズできません。また、POFオブジェクト参照では循環参照がサポートされます。そのため、キー・クラスに循環参照が含まれないようにする必要があります。