この章の内容は次のとおりです。
シリアライズとは、オブジェクトをバイナリ形式にエンコードするプロセスです。ネットワークを介してデータを移動する必要があるため、これはCoherenceの操作に不可欠なコンポーネントです。POFは言語に依存しないバイナリ形式です。POFは領域と時間の両面で効率を向上させるように設計されており、Coherenceの使用時に不可欠なものとなっています。POFバイナリ・ストリームの詳細は、PIF-POFバイナリ形式を参照してください。
シリアライズで使用可能なオプションには、標準Javaシリアライズ、POF、独自のカスタム・シリアライズ・ルーチンなどいくつかあります。各オプションには、それぞれトレードオフがあります。標準Javaシリアライズは簡単に実装可能であり、循環オブジェクト・グラフをサポートし、オブジェクトIDを保持します。ただし、比較的動作が低速で、冗長なバイナリ形式が使用され、Javaオブジェクトのみが処理対象となります。
POFには、次の利点があります。
現在はJava、.NETおよびC++をサポートしており、言語に依存しません。
非常に効率的です。1つのString、1つのlongおよび3つのintを備えた簡単なテスト・クラスでは、標準のJavaシリアライズと比較して、シリアライズおよびデシリアライズが7倍高速化され、生成されるバイナリのサイズが1/6になります。
バージョニングが可能です。オブジェクトの向上を図ることが可能であり、上位および下位の互換性があります。
シリアライズ・ロジックを外部化できます。
索引付けされ、オブジェクト全体をデシリアライズせずに値を抽出できます。POFエクストラクタとPOFアップデータの使用を参照してください。
POFには、オブジェクトのシリアライズおよびデシリアライズの方法を認識するシリアライズ・ルーチンの実装が必要です。オブジェクトのシリアライズには、com.tangosol.io.pof.PortableObjectインタフェースとcom.tangosol.io.pof.PofSerializerインタフェースという2つのインタフェースが使用可能です。POFは、PortableObjectまたはPofSerializerインタフェースを実装せずにシリアライズを自動的に実装する注釈もサポートしています。詳細は、オブジェクトをシリアライズするためのPOF注釈の使用を参照してください。
この項には次のトピックが含まれます:
PortableObjectインタフェースは、次の2つのメソッドで構成されるインタフェースです。
public void readExternal(PofReader reader)
public void writeExternal(PofWriter writer)
POFストリームに対する書込みまたは読取りを行う各要素に数値を指定することで、POF要素に索引が付けられます。索引はPOFストリームにおいて書込みと読取りが実行される各要素に対して一意である必要があります。索引はスーパー・クラスと派生クラスの間で一意である必要があるため、派生タイプが存在する場合には特に注意が必要です。次の例では、PortableObjectインタフェースの実装を示します。
public void readExternal(PofReader in)
throws IOException
{
m_symbol = (Symbol) in.readObject(0);
m_ldtPlaced = in.readLong(1);
m_fClosed = in.readBoolean(2);
}
public void writeExternal(PofWriter out)
throws IOException
{
out.writeObject(0, m_symbol);
out.writeLong(1, m_ldtPlaced);
out.writeBoolean(2, m_fClosed);
}
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);
}
POFの索引をオブジェクトの属性に割り当てるときには、次のガイドラインに従ってください。
読取りと書込みの順序: シリアライズ・ルーチンの最低索引値から開始して、最高索引値で終了します。値をデシリアライズする場合には、書込みと同じ順序で読取りを実行します。
非連続の索引を指定することはできますが、読取りまたは書込みが連続して実行される必要があります。
サブクラス作成時に索引の範囲を予約する場合: 索引は派生タイプ間で累積されます。そのため、各派生タイプがそのスーパークラスで予約されたPOF索引範囲を認識する必要があります。
索引を他の目的に使用しない: 進化をサポートするためには、クラス・リビジョン全体で属性の索引を他の目的に使用しないようにすることが必須です。
ラベルの索引: public static final intでラベル付けされている索引は、さらに簡単に使用できます。特に、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番目のリストで読み取られる必要があります。
この項には次のトピックが含まれます:
オブジェクト参照は、デフォルトでは無効になっており、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);
循環構造のオブジェクトやネストされたオブジェクトは、オブジェクトの作成時に手動で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;
}
}
Coherenceには、com.tangosol.io.pof.ConfigurablePofContextシリアライザ・クラスが用意されていて、それによりPOFのシリアライズ・オブジェクトが適切なシリアライズ・ルーチン(PofSerializer実装、またはPortableObjectインタフェースを介した呼び出しによる)にマップされます。
クラスにシリアライズ・ルーチンが指定されると、そのクラスはpof-config.xml構成ファイルを使用してConfigurablePofContextクラスに登録されます。POF構成ファイルには<user-type-list要素があり、それにはPortableObjectを実装するクラスまたはそれらに関連付けられているPofSerializerを持つクラスのリストが記載されています。各クラスに対する<type-idは一意である必要があり、すべてのクラスタ・インスタンス(拡張クライアントを含む)で一致している必要があります。POFの構成要素の詳細は、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構成ファイルに含まれている必要があります。
CoherenceでConfigurablePofContextシリアライザ・クラスを使用する場合には、必要な精度のレベルに基づいた、次の3通りの構成が可能です。
サービスごと - 各サービスには、ConfigurablePofContextシリアライザ・クラスの完全な構成が用意されており、オペレーション構成ファイルにある事前定義済の構成が参照されます。
すべてのサービス - すべてのサービスでグローバルConfigurablePofContextシリアライザ・クラスの構成が使用されます。独自の構成を提供するサービスによってグローバルな構成がオーバーライドされます。グローバル構成を完全構成にして、オペレーション構成ファイルに含まれる事前定義済の構成を参照することも可能です。
JVM - ConfigurablePofContextシリアライザ・クラスはJVM全体に対して有効化されます。
ConfigurablePofContextクラスを使用するようにサービスを構成するには、キャッシュ構成ファイルのキャッシュ・スキームに<serializer>要素を追加します。<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>
次の例では、オペレーション構成ファイルのデフォルトの定義を参照します。デフォルトのConfigurablePofContextシリアライザ定義を確認するには、serializerを参照してください。
<distributed-scheme>
<scheme-name>example-distributed</scheme-name>
<service-name>DistributedCache</service-name>
<serializer>pof</serializer>
</distributed-scheme>
ConfigurablePofContextクラスをすべてのサービスに対してグローバルに構成するには、キャッシュ構成ファイルの<defaults>要素内に<serializer>要素を追加します。次の例は両方とも、シリアライザをすべてのキャッシュ・スキームの定義に対してグローバルに構成するものであり、個々のキャッシュ・スキームの定義内にその他の構成を追加する必要はありません。<defaults>要素の完全なリファレンスは、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>
...
次の例では、オペレーション構成ファイルのデフォルトの定義を参照します。デフォルトのConfigurablePofContextシリアライザ定義を確認するには、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>
...
次のシステム・プロパティを使用して、POFを使用するようにJVMインスタンス全体を構成できます。
coherence.pof.enabled=true - JVMインスタンス全体でPOFを有効化します。
coherence.pof.config=CONFIG_FILE_PATH - 使用するPOF構成ファイルへのパスです。このファイルがクラスパスにない場合には、ファイル・リソースとして存在するはずです(例: file:///opt/home/coherence/mycustom-pof-config.xml)。
POF注釈は、オブジェクトにシリアライズやデシリアライズ・ルーチンの実装を自動化する方法を提供します。POF注釈は、PofSerializerインタフェースの実装であるPofAnnotationSerializerクラスを使用してシリアライズまたはデシリアライズします。注釈は、PortableObjectおよびPofSerializerインタフェースの使用に代わる手段を提供し、オブジェクトをシリアライズ可能なものにするために必要な時間とコードを削減します。
この項には次のトピックが含まれます:
クラスとクラスのプロパティがPOFシリアライズ可能であることを示すために利用できる注釈は2つあります。
@Portable – クラスをPOFシリアライズ可能としてマークします。注釈は、クラス・レベルのみに使用でき、メンバーを含みません。
@PortableProperty – メンバー変数またはメソッド・アクセッサをPOFシリアライズ可能属性としてマークします。注釈が付けられたメソッドは、アクセッサの表記法(get、set、is)に従っている必要があります。メンバーを、POF索引や、シリアライズまたはデシリアライズの前後で実行するカスタム・コーデックの指定に使用できます。索引の値は省略可能で、自動的に割り当てられます。カスタム・コーデックを入力しない場合は、デフォルトのコーデックが使用されます。
次の例では、クラス、メソッドおよびプロパティの注釈付け、およびプロパティの索引値の明示的な割当てを示します。POF索引付けの詳細は、POF索引の割当てのガイドラインを参照してください。
@Portable
public class Person
{
@PortableProperty(0)
public String getFirstName()
{
return m_firstName;
}
private String m_firstName;
@PortableProperty(1)
private String m_lastName;
@PortableProperty(2)
private int m_age;
}
POF注釈付きオブジェクト(すべてのPOFオブジェクトなど)は、pof-config.xmlファイルの<user-type>要素内に登録されている必要があります。POFの構成要素の詳細は、POFユーザー定義型の構成要素を参照してください。POF構成ファイルを手動で作成するかわりに、POF構成ジェネレータ・ツールを使用して、@Portable注釈を使用するオブジェクトに基づいて自動的にPOF構成ファイルを作成できます。POF構成ジェネレータ・ツールの詳細は、POF構成ファイルの生成を参照してください。
POF注釈付きオブジェクトは、オブジェクトがPortableObjectを実装しておらず、Portableとして注釈が付けられている場合は、PofAnnotationSerializerシリアライザを使用します。ただし、オブジェクトに注釈が付けられており、ユーザー定義型の定義に含める必要がない場合は、自動的にシリアライザが使用されます。次の例では、注釈付きPersonオブジェクトのユーザー定義型を登録します。
<?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.Person</class-name>
</user-type>
</user-type-list>
</pof-config>
POF構成ジェネレータ・コマンド行ツールは、@Portable注釈が含まれるクラスのユーザー定義型エントリを含むPOF構成ファイルを自動的に作成します。このツールは、POF構成ファイルを手動で作成するかわりとなり、ビルド・プロセスの一部として最適です。
POF構成ジェネレータ・コマンド行ツールを起動するには、COHERENCE_HOME/bin/pof-config-genスクリプト(.cmdまたは.sh)を使用するか、com.tangosol.io.pof.generator.Executorクラスを直接実行します。詳細な使用方法を確認するには、-help引数を使用します。使用方法を次に示します。
pof-config-gen [OPTIONS] -root
-root引数は必須で、POF注釈付きのクラスをスキャンする場所(別々のディレクトリ、JARファイルまたはGARファイル)をリストします。見つかった注釈付きのクラスのそれぞれにつき、ユーザー定義型のエントリおよびIDが生成され、結果として生成されたpof-config.xmlファイルが現在の作業ディレクトリに書き込まれます。次に例を示します。
pof-config-gen.cmd -root c:\src\myPofClasses.jar
注意:
GARファイルをルートとして指定した場合、出力はカウント接尾辞の付いた新しいGARファイル(filename-n.gar)で、このファイルに生成されたPOF構成ファイルが含まれます。
次のオプションの引数を指定できます。
-out: -out引数を使用して、出力ディレクトリのパス、またはパスとファイル名を指定します。デフォルトの出力ディレクトリは作業ディレクトリです。ディレクトリのみを指定した場合のデフォルトのファイル名は、pof-config.xmlです。ディレクトリを指定した場合にpof-config.xmlファイルがすでに存在する場合は、カウント接尾辞の付いた新しいファイルが作成されます(pof-config-n.xml)。パスとファイル名を指定した場合にそのファイルが現在存在する場合は、ファイルが上書きされます。
-config: -config引数を使用して、既存のPOF構成ファイルのパスとファイル名を指定し、そのファイルに含まれる既存のユーザー定義型を生成されるPOF構成ファイルに追加します。既存のユーザー定義型のIDは、生成されたファイルで保持されます。POF構成ファイルを複数回生成する場合、この引数を使用して後方互換性をサポートできます。
-include: -include引数を使用して、生成されるPOF構成ファイル内で(-config引数で指定された)既存のPOF構成ファイルの参照のみを行うかどうかを指定します。この引数を使用すると、既存のファイルを参照する<include>要素が生成されます。既存のユーザー定義型およびIDは、生成されるファイルに再作成されません。実行時には、クラスパスに参照先のファイルを配置する必要があります。
注意:
既存のPOF構成ファイル内にCoherence固有のPOF構成ファイル(coherence-pof-config.xml)への参照が見つからない場合は、-include引数の使用によって、生成されるPOF構成ファイルにこの参照を追加する必要がなくても、この参照は自動的に追加されます。
-packages: -packages引数を使用して、クラスのスキャンを特定のパッケージに制限します。パッケージはカンマ区切りリストで入力します。
-startTypeId: -startTypeId引数を使用して、ユーザー定義型のIDの割当てを開始する際のID番号を指定します。1000までのIDは、Coherence固有のタイプ用に予約されているため、使用できません。
次の例では、c:\classes\pofディレクトリをスキャンし、新しいPOF構成ファイルをmy-pof-config.xmlという名前でc:\tmpディレクトリに作成しますが、このファイルには(参照によって)既存のc:\tmp\pof-config.xmlファイルがインクルードされます。
pof-config-gen.cmd -out c:\tmp\my-pof-config.xml -config c:\tmp\pof-config.xml -include -root c:\classes\pof
POF注釈では、自動索引付けがサポートされており、明示的な索引値の割当てや管理の必要性を軽減されます。@PortableProperty注釈を定義する場合は、索引値を省略します。索引の割当てはプロパティ名によって決定されます。明示的に索引値を割り当てるプロパティによって、自動索引値が割り当てられることはありません。次の表は、自動索引アルゴリズムの命令セマンティクスを示しています。自動索引付けは、明示的に定義された索引を維持し(プロパティc参照)、索引が省略されている場合は、索引を割り当てます。
| プロパティ名 | 明示的な索引 | 決定された索引 |
|---|---|---|
c |
1 |
1 |
a |
omitted |
0 |
b |
omitted |
2 |
注意:
自動索引では、現在、進化可能なクラスがサポートされていません。
自動索引付けを有効にするには、POF構成ファイルでユーザー定義型としてオブジェクトを登録するときにPofAnnotationSerializerシリアライザ・クラスを明示的に定義する必要があります。コンストラクタ内のfAutoIndexブール・パラメータは、自動索引付けを有効にするもので、trueに設定する必要があります。次に例を示します。
<user-type>
<type-id>1001</type-id>
<class-name>com.examples.Person</class-name>
<serializer>
<class-name>com.tangosol.io.pof.PofAnnotationSerializer</class-name>
<init-params>
<init-param>
<param-type>int</param-type>
<param-value>{type-id}</param-value>
</init-param>
<init-param>
<param-type>class</param-type>
<param-value>{class}</param-value>
</init-param>
<init-param>
<param-type>boolean</param-type>
<param-value>true</param-value>
</init-param>
</init-params>
</serializer>
</user-type>
コーデックによって、シリアライズまたはデシリアライズの前後でコードを実行できます。コーデックでは、PofWriterおよびPofReaderインタフェースを使用して、移植可能なプロパティをエンコードおよびデコードする方法を定義できます。コーデックは、一般に、デシリアライズ中に消失する可能性がある実用的な実装に使用します。または、オブジェクトをシリアライズする前にPofWriterインタフェースで特定のメソッドを明示的にコールするために使用します。
コーディックを作成するには、com.tangosol.io.pof.reflect.Codecインタフェースを実装するクラスを作成します。次の例は、リンクされたリスト型の実用的な実装を定義するコーデックを示しています。
public static class LinkedListCodec implements Codec
{
public Object decode(PofReader in, int index) throws IOException
{
return (List<String>) in.readCollection(index, new LinkedList<String>());
}
public void encode(PofWriter out, int index, Object value) throws IOException
{
out.writeCollection(index, (Collection) value);
{
}
プロパティにコーディックを割り当てるには、コーディックを@PortableProperty注釈のメンバーとして入力します。コーデックを指定しない場合は、デフォルトのコーデック(DefaultCodec)が使用されます。次の例は、前述のLinkedListCodecコーデックの割当て方法を示しています。
@PortableProperty(codec = LinkedListCodec.class) private List<String> m_aliases;
Coherenceでは、ValueExtractorインスタンスとValueUpdaterインスタンスを使用して、キャッシュに格納されたオブジェクトの値が抽出および更新されます。PofExtractorインスタンスとPofUpdaterインスタンスは、POFの索引付けされた状態を利用して、シリアライズ・ルーチンまたはデシリアライズ・ルーチン全体を実行せずにオブジェクトを抽出または更新します。
PofExtractorとPofUpdaterにより、Coherenceの非プリミティブ・タイプを使用するときの柔軟性が向上します。多くの拡張クライアントの場合、グリッド内に対応するJavaクラスは不要です。POFエクストラクタとPOFアップデータはバイナリをナビゲートできるため、キーと値全体をオブジェクト形式にデシリアライズしなくても済みます。これは、索引付けする値をPOFエクストラクタを使用してプルするだけで索引付けできることを意味します。ただし、キャッシュ・ストアを使用している場合は、対応するJavaクラスが必要です。この場合、キーと値のデシリアライズ・バージョンがキャッシュ・ストアに渡され、バックエンドに書き込まれます。
POFは索引付けされているため、バイナリを抽出用または更新用の特定の要素まで迅速に横断できます。POF値オブジェクトを横断し、目的のPOF値オブジェクトを返すのは、PofNavigatorインタフェースの役目です。Coherenceには、初期状態で、整数索引に基づいてPOF値を移動できるSimplePofPathクラスが用意されています。最も簡単な形式では、抽出または更新する属性の索引を提供します。次の例を参照してください。
public class Contact
implements PortableObject
{
...
// ----- PortableObject interface ---------------------------------------
public void readExternal(PofReader reader)
throws IOException
{
m_sFirstName = reader.readString(FIRSTNAME);
m_sLastName = reader.readString(LASTNAME);
m_addrHome = (Address) reader.readObject(HOME_ADDRESS);
m_addrWork = (Address) reader.readObject(WORK_ADDRESS);
m_mapPhoneNumber = reader.readMap(PHONE_NUMBERS, null);
}
public void writeExternal(PofWriter writer)
throws IOException
{
writer.writeString(FIRSTNAME, m_sFirstName);
writer.writeString(LASTNAME, m_sLastName);
writer.writeObject(HOME_ADDRESS, m_addrHome);
writer.writeObject(WORK_ADDRESS, m_addrWork);
writer.writeMap(PHONE_NUMBERS, m_mapPhoneNumber);
}
....
// ----- constants -------------------------------------------------------
public static final int FIRSTNAME = 0;
public static final int LASTNAME = 1;
public static final int HOME_ADDRESS = 2;
public static final int WORK_ADDRESS = 3;
public static final int PHONE_NUMBERS = 4;
...
}
POFストリームへの書込みまたはPOFストリームからの書込みを実行中の各データ・メンバーに対する定数が存在することに注意してください。この方法に従えば、POFエクストラクタとPOFアップデータを容易に使用できてシリアライズ・ルーチンの書込みも簡素化されるという、優れた利点が得られます。各索引にラベルを付けることで、索引の操作はさらに容易になります。前述のように、最も簡単な場合では、WORK_ADDRESS索引を使用して連絡先から勤務先のアドレスを抽出できます。SimplePofPathにより、intsのArrayを使用してPofValuesを横断できるようになります。たとえば、勤務先のアドレスの郵便番号を取得するには、[WORK_ADDRESS, ZIP]を使用します。次の例で、詳細を示します。
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エクストラクタと同じ方法で動作します。姓が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ではクロス・プラットフォームのオブジェクト形式を定義しますが、必ずしも対称的な変換を提供できるわけではありません。すなわち、シリアライズ・オブジェクトをデシリアライズすると、オブジェクトの型は元の型と異なります。これは、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オブジェクト参照では循環参照がサポートされます。そのため、キー・クラスに循環参照が含まれないようにする必要があります。