ヘッダーをスキップ
Oracle® Coherenceクライアント・ガイド
リリース3.7.1
B65027-01
  ドキュメント・ライブラリへ移動
ライブラリ
製品リストへ移動
製品
目次へ移動
目次

前
 
次
 

18 統合オブジェクトの構築(.NET)

Coherenceキャッシュは、値オブジェクトをキャッシュするために使用されます。.NETクライアントがCoherence JVMと正常に通信するためには、プラットフォームに依存しないシリアライズ形式が必要になります。これにより、.NETクライアントとCoherence JVM(Coherence*Extend Javaクライアントを含む)の両方で、Coherenceキャッシュに格納されている値オブジェクトを正しくシリアライズおよびデシリアライズできるようになります。Coherence for .NETクライアント・ライブラリおよびCoherence*Extendクラスタ・サービスでは、Portable Object Format(POF)というシリアライズ形式が使用されます。POFを使用すると、値オブジェクトのプラットフォームおよび元の言語と関係ない方法で、値オブジェクトをバイナリ・ストリームにエンコードできます。POFバイナリ・ストリームの詳細は、『Oracle Coherence開発者ガイド』を参照してください。

この章は次の各項で構成されています。

18.1 統合オブジェクトの構築(.NET)の概要

POFでは、共通の.NET型がすべてそのままサポートされます。カスタムの.NETクラスも次の手順でPOFストリームにシリアライズできます

  1. IPortableObjectインタフェースを実装する.NETクラスを作成します(「IPortableObject実装の作成」を参照)。

  2. 同様に、PortableObjectインタフェースを実装する、対応するJavaクラスを作成します(「PortableObject実装の作成(Java)」を参照)。

  3. カスタムの.NETクラスをクライアントに登録します(「.NETクライアントでのカスタム型の登録」を参照)。

  4. Coherence*Extendクラスタ・サービスを実行している各サーバーにカスタムのJavaクラスを登録します(「クラスタでのカスタム型の登録」を参照)。

ここまでの手順が完了すると、組込みのデータ型と同じようにカスタムの.NETクラスをCoherenceキャッシュにキャッシュできるようになります。さらに対応するJavaクラスを使用すれば、それらの型をCoherenceまたはCoherence*Extend JVMから取得し、操作して、格納できます。

18.2 IPortableObject実装の作成

IPortableObjectを実装する各クラスは、自身の状態をPOFデータ・ストリームにシリアライズし、POFデータ・ストリームからデシリアライズできます。この処理は、ReadExternalメソッド(デシリアライズ)およびWriteExternalメソッド(シリアライズ)で行われます。概念上は、すべてのユーザー定義型が0個以上の索引付き値(プロパティ)で構成されており、それらが1つずつPOFデータ・ストリームから読み取られ、POFデータ・ストリームに書き込まれます。移植可能なクラスには、IPortableObjectインタフェースの実装が必要であること以外の唯一の要件として、デフォルト・コンストラクタが必要です。これにより、POFデシリアライザで、デシリアライズ時にクラスのインスタンスを作成できるようになります。

例18-1は、移植可能なユーザー定義クラスを示しています。

例18-1 移植可能なユーザー定義クラス

public class ContactInfo : IPortableObject
{
    private string name;
    private string street;
    private string city;
    private string state;
    private string zip;
    public ContactInfo()
    {}

    public ContactInfo(string name, string street, string city, string state, string zip)
    {
        Name   = name;
        Street = street;
        City   = city;
        State  = state;
        Zip    = zip;
    }
    public void ReadExternal(IPofReader reader)
    {
        Name   = reader.ReadString(0);
        Street = reader.ReadString(1);
        City   = reader.ReadString(2);
        State  = reader.ReadString(3);
        Zip    = reader.ReadString(4);
    }
    public void WriteExternal(IPofWriter writer)
    {
        writer.WriteString(0, Name);
        writer.WriteString(1, Street);
        writer.WriteString(2, City);
        writer.WriteString(3, State);
        writer.WriteString(4, Zip);
    }
    // property definitions ommitted for brevity
}

18.3 Javaバージョンの.NETオブジェクトの実装

POFの使用によって、並列のJava実装を必要とせずに、キーおよび値オブジェクトをクラスタ内に格納できます。これは、基本的なgetとputベースの操作を実行する場合に適しています。さらに、PofExtractorおよびPofUpdater APIでシリアライズされたオブジェクトを直接操作することにより、並列のJava実装が特定の状況で必要なくなります。ただし、高度なデータ・グリッド機能を使用する場合は、データ・オブジェクトのシリアライズ表現を保持するのではなく、Javaベースのキャッシュ・サーバーを使用してデータ・オブジェクトと対話できる必要があります。Java実装は、キャッシュ・サーバーに配置される必要があり、オブジェクトと対話し、そのプロパティにアクセスするために使用します。JavaバージョンのPOFでシリアライズ可能にする方法は前述の例とほぼ同じで、「PortableObject実装の作成(Java)」で説明されています。詳細は、com.tangosol.io.pof.PortableObjectcom.tangosol.io.pof.PofSerializerのAPIを参照してください。これらのAPIは、.NETの方法と互換性があります。

並列のJava実装の組込みが必要になる状況

基本的なgetとputの操作よりも高度な多くのデータ・グリッド機能では、オブジェクトがクラスタ内に並列のJava実装を持つことを必要とします。これらの機能は、次のとおりです。

キーの関連付けチェックの遅延

キー・クラスは、クラスタ側Java実装を必要としません。これはIKeyAssociationインタフェースを使用してデータのアフィニティを指定している場合でも同様です。キー・クラスは、クライアント側でチェックされ、修飾されたバイナリがクラスタによって作成および使用されます。ただし、キーの関連付けをJavaキー・クラスに依存している既存のクライアント実装は、Javaキー・クラスの使用を強制するためにdefer-key-association-checkパラメータを設定する必要があります。キーの関連付けを使用する既存クライアント・アプリケーションで、クライアント側のキー・バイナリを利用する場合は、getAssociatedKey()実装を既存のJavaクラスから対応するクライアント・クラスに移植する必要があります(IKeyAssociation.AssociatedKeyを参照)。

キーの関連付け処理をExtendクライアントによってではなくクラスタ側で実行するには、クライアント側キャッシュの構成で<remote-cache-scheme>要素の<defer-key-association-check>要素をtrueに設定します。例:

<remote-cache-scheme>
   ...
   <defer-key-association-check>true</defer-key-association-check>
</remote-cache-scheme>

注意:

パラメータがtrueに設定されている場合、Javaキー・クラス実装は、キーの関連付けを使用していない場合でも、クラスタに存在する必要があります。

18.3.1 PortableObject実装の作成(Java)

Javaでの移植可能なクラスの実装は、.NETでの実装と非常によく似ています。例18-2は、例18-1の.NETクラスをJavaで実現した場合を示しています。

例18-2 Javaでのユーザー定義クラス

public class ContactInfo implements PortableObject
    {    private String m_sName;

    private String m_sStreet;
    private String m_sCity;
    private String m_sState;
    private String m_sZip;
    public ContactInfo()
        {
        }
    public ContactInfo(String sName, String sStreet, String sCity, String sState, String sZip)
        {
        setName(sName);
        setStreet(sStreet);
        setCity(sCity);
        setState(sState);
        setZip(sZip);
        }
    public void readExternal(PofReader reader)
            throws IOException
        {
        setName(reader.readString(0));
        setStreet(reader.readString(1));
        setCity(reader.readString(2));
        setState(reader.readString(3));
        setZip(reader.readString(4));
        }
    public void writeExternal(PofWriter writer)
            throws IOException
        {
        writer.writeString(0, getName());
        writer.writeString(1, getStreet());
        writer.writeString(2, getCity());
        writer.writeString(3, getState());
        writer.writeString(4, getZip());
        }
    // accessor methods omitted for brevity
}

18.4 .NETクライアントでのカスタム型の登録

各POFユーザー定義型は、POFストリーム内で整数値として表されます。したがって、POFには、ユーザー定義型をそのエンコードされた型識別子に(またはその逆方向に)マップするための外部メカニズムが必要です。このメカニズムでは、XML構成ファイルを使用してマッピング情報が格納されます。これを例18-3に示します。POFの構成要素の詳細は、『Oracle Coherence開発者ガイド』を参照してください。

例18-3 POFユーザー定義型構成ファイルへのマッピング情報の格納

<?xml version="1.0"?>
<pof-config xmlns="http://schemas.tangosol.com/pof">
   <user-type-list>
    <!-- include all "standard" Coherence POF user types -->
      <include>assembly://Coherence/Tangosol.Config/coherence-pof-config.xml
      </include>
    <!-- include all application POF user types -->
      <user-type>
         <type-id>1001</type-id>
         <class-name>My.Example.ContactInfo, MyAssembly</class-name>
      </user-type>
   </user-type-list>
</pof-config>

次の点に注意してください。

型識別子とカスタム型の間のマッピングを構成したら、キャッシュ構成ディスクリプタにserializer要素を追加して、それらのマッピングを使用するようCoherence for .NETを構成する必要があります。たとえば、例18-3に示したユーザー定義型のマッピングがmy-dotnet-pof-config.xmlに保存されている場合は、例18-4に示すようにserializer要素を指定する必要があります。

例18-4 キャッシュ構成ファイルでのserializerの使用

<remote-cache-scheme>
   <scheme-name>extend-direct</scheme-name>
   <service-name>ExtendTcpCacheService</service-name>
   <initiator-config>
   ...
      <serializer>
         <class-name>Tangosol.IO.Pof.ConfigurablePofContext, Coherence
         </class-name>
         <init-params>
            <init-param>
               <param-type>string</param-type>
               <param-value>my-dotnet-pof-config.xml</param-value>
            </init-param>
         </init-params>
      </serializer>
   </initiator-config>
</remote-cache-scheme>

シリアライザを明示的に指定しない場合は、ConfigurablePofContext型がPOFシリアライザとして使用されます。これはpof-config.xmlというデフォルトの構成ファイルを使用します。Coherence .NETアプリケーションでは、アプリケーションのデプロイ先フォルダと、Webアプリケーションの場合はWebアプリケーションのルートの両方で、デフォルトのPOF構成ファイルが検索されます。POF構成ファイルが見つからない場合は、Coherence for .NETアプリケーション構成ファイルのpof-config要素の内容によるファイルの特定が試行されます。例:

例18-5 POF構成ファイルの指定

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="coherence" type="Tangosol.Config.CoherenceConfigHandler, Coherence"/>
  </configSections>
  <coherence>
    <pof-config>my-dotnet-pof-config.xml</pof-config>
  </coherence>
</configuration>

18.5 クラスタでのカスタム型の登録

TCP/IP Coherence*Extendクラスタ・サービスを実行しているCoherenceノードでカスタム型のオブジェクトを送受信できるようにするには、各ノードに、カスタム型の類似したPOF構成ファイルが必要です。

クラスタ側のPOF構成ファイルは、クライアントで作成された構成ファイルと似ています。唯一の違いは、class-name要素で.NETクラス名のかわりに完全修飾されたJavaクラス名を指定する必要がある点です。

例18-6は、クラスタ側のPOF構成ファイルのサンプル(my-java-pof-config.xml)を示しています。

例18-6 クラスタ側の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 all "standard" Coherence POF user types -->
      <include>coherence-pof-config.xml</include>
   <!-- include all application POF user types -->
      <user-type>
         <type-id>1001</type-id>
         <class-name>com.mycompany.example.ContactInfo</class-name>
      </user-type>
   </user-type-list>
</pof-config>

カスタム型を追加したら、オブジェクトのシリアライズ時に各自のPOF構成ファイルが使用されるようサーバーを構成する必要があります。これを例18-7に示します。

例18-7 POF構成ファイルを使用するためのサーバーの構成

<proxy-scheme>
   <service-name>ExtendTcpProxyService</service-name>
   <acceptor-config>
   ...
      <serializer>
         <class-name>com.tangosol.io.pof.ConfigurablePofContext</class-name>
         <init-params>
            <init-param>
               <param-type>string</param-type>
               <param-value>my-java-pof-config.xml</param-value>
            </init-param>
         </init-params>
      </serializer>
   </acceptor-config>
  ...
</proxy-scheme>

18.6 進化可能な移植性のあるユーザー定義型

PIF-POFは、シリアライズされた形式の移植可能なユーザー定義型の上位互換性および下位互換性をネイティブにサポートします。.NETでは、ユーザー定義型でIPortableObjectインタフェースのかわりにIEvolvablePortableObjectインタフェースを実装することで、このサポートが実現します。IEvolvablePortableObjectインタフェースは、IPortableObjectIEvolvableの両方のインタフェースを拡張するマーカー・インタフェースです。IEvolvableインタフェースは、型のバージョニングをサポートする3つのプロパティを追加します。IEvolvableクラスには整数のバージョン識別子n(n >= 0)が含まれていますシリアライズされた形式のIEvolvableクラスのコンテンツ、セマンティクス、またはそれら両方が変更されると、このバージョン識別子が引き上げられます。2つのバージョン識別子n1n2は、n1 == n2であれば同じバージョンを示し、n2 > n1であればn2のバージョンがn1のバージョンより新しいことを示します。

IEvolvableインタフェースは、データの追加による型の進化をサポートするように設計されています。あるデータに前のバージョンの型が依存している場合、そのデータを安全に削除することはできません。同様に、データの前の構造またはセマンティクスに前のバージョンの型が依存している場合、そのデータの構造またはセマンティクスを前のバージョンから安全に変更することはできません。

IEvolvableオブジェクトがデシリアライズされる場合は、新しいバージョンの型に追加された未知のデータ、およびそのデータ形式のバージョン識別子が保持されます。その後、このIEvolvableオブジェクトがシリアライズされると、保持されたバージョン識別子と未知の将来データがオブジェクトに取り込まれます。

古いバージョンを示すバージョン識別子を持つデータ・ストリームからIEvolvableオブジェクトをデシリアライズする場合は、その古いバージョン以降に追加されたデータ・フィールドやプロパティの値をデフォルトに設定し、計算する必要があります。その後、このIEvolvableオブジェクトがシリアライズされると、そのバージョン識別子と全データがオブジェクトに取り込まれます。この場合は未知の将来データがないことに注意してください。将来データは、データ・ストリームのバージョンがIEvolvable型のバージョンよりも新しい場合にのみ存在します。

例18-8は、クラスの進化をサポートするように.NET型のContactInfoを変更する方法を示しています。

例18-8 クラスの進化をサポートするようにクラスを変更する

public class ContactInfo : IEvolvablePortableObject
{
    private string name;
    private string street;
    private string city;
    private string state;
    private string zip;
    // IEvolvable members
    private int    version;
    private byte[] data;
    public ContactInfo()
    {}
    public ContactInfo(string name, string street, string city, string state, string zip)
    {
        Name   = name;
        Street = street;
        City   = city;
        State  = state;
        Zip    = zip;
    }
    public void ReadExternal(IPofReader reader)
    {
        Name   = reader.ReadString(0);
        Street = reader.ReadString(1);
        City   = reader.ReadString(2);
        State  = reader.ReadString(3);
        Zip    = reader.ReadString(4);
    }
    public void WriteExternal(IPofWriter writer)
    {
        writer.WriteString(0, Name);
        writer.WriteString(1, Street);
        writer.WriteString(2, City);
        writer.WriteString(3, State);
        writer.WriteString(4, Zip);
    }
    public int DataVersion
    {
        get { return version; }
        set { version = value; }
    }
    public byte[] FutureData
    {
        get { return data; }
        set { data = value; }
    }
    public int ImplVersion
    {
        get { return 0; }
    }
    // property definitions ommitted for brevity
}

同様に、Java型のContactInfoは、EvolvablePortableObjectインタフェースを実装することでクラスの進化をサポートするように変更できます。

例18-9 クラスの進化をサポートするようにJava型のクラスを変更する

public class ContactInfo
        implements EvolvablePortableObject
    {
    private String m_sName;
    private String m_sStreet;
    private String m_sCity;
    private String m_sState;
    private String m_sZip;

    // Evolvable members
    private int    m_nVersion;
    private byte[] m_abData;

    public ContactInfo()
        {}

    public ContactInfo(String sName, String sStreet, String sCity,
            String sState, String sZip)
        {
        setName(sName);
        setStreet(sStreet);
        setCity(sCity);
        setState(sState);
        setZip(sZip);
        }

    public void readExternal(PofReader reader)
            throws IOException
        {
        setName(reader.readString(0));
        setStreet(reader.readString(1));
        setCity(reader.readString(2));
        setState(reader.readString(3));
        setZip(reader.readString(4));
        }

    public void writeExternal(PofWriter writer)
            throws IOException
        {
        writer.writeString(0, getName());
        writer.writeString(1, getStreet());
        writer.writeString(2, getCity());
        writer.writeString(3, getState());
        writer.writeString(4, getZip());
        }

    public int getDataVersion()
        {
        return m_nVersion;
        }

    public void setDataVersion(int nVersion)        {
        m_nVersion = nVersion;
        }

    public Binary getFutureData()
        {
        return m_binData;
        }

    public void setFutureData(Binary binFuture)
        {
        m_binData = binFuture;
        }

    public int getImplVersion()
        {
        return 0;
        }

    // accessor methods omitted for brevity
    }

18.7 変更なしで型を移植可能にする

既存のユーザー定義型を移植可能にする変更が望ましくない場合、または不可能な場合があります。その場合は、IPofSerializerの実装(.NET)、PofSerializerインタフェースの実装(Java)、またはその両方を作成することで、ユーザー定義型の移植可能なシリアライズを外部化できます。

例18-10は、ContactInfoIPofSerializerインタフェースの実装を示しています。

例18-10 .NET型のIPofSerializerの実装

public class ContactInfoSerializer : IPofSerializer
{
    public object Deserialize(IPofReader reader)
    {
        string name   = reader.ReadString(0);
        string street = reader.ReadString(1);
        string city   = reader.ReadString(2);
        string state  = reader.ReadString(3);
        string zip    = reader.ReadString(4);

        ContactInfo info = new ContactInfo(name, street, city, state, zip);
        info.DataVersion = reader.VersionId;
        info.FutureData  = reader.ReadRemainder();

        return info;
    }

    public void Serialize(IPofWriter writer, object o)
    {
        ContactInfo info = (ContactInfo) o;

        writer.VersionId = Math.Max(info.DataVersion, info.ImplVersion);
        writer.WriteString(0, info.Name);
        writer.WriteString(1, info.Street);
        writer.WriteString(2, info.City);
        writer.WriteString(3, info.State);
        writer.WriteString(4, info.Zip);
        writer.WriteRemainder(info.FutureData);
    }
}

Java型のContactInfoPofSerializerインタフェースの実装は次のようになります。

例18-11 Java型クラスのPofSerializerの実装

public class ContactInfoSerializer
        implements PofSerializer
    {
    public Object deserialize(PofReader in)
            throws IOException
        {
        String sName   = in.readString(0);
        String sStreet = in.readString(1);
        String sCity   = in.readString(2);
        String sState  = in.readString(3);
        String sZip    = in.readString(4);

        ContactInfo info = new ContactInfo(sName, sStreet, sCity, sState, sZip);
        info.setDataVersion(in.getVersionId());
        info.setFutureData(in.readRemainder());

        return info;
        }

    public void serialize(PofWriter out, Object o)
            throws IOException
        {
        ContactInfo info = (ContactInfo) o;

        out.setVersionId(Math.max(info.getDataVersion(), info.getImplVersion()));
        out.writeString(0, info.getName());
        out.writeString(1, info.getStreet());
        out.writeString(2, info.getCity());
        out.writeString(3, info.getState());
        out.writeString(4, info.getZip());
        out.writeRemainder(info.getFutureData());
        }
    }

.NET型のContactInfoIPofSerializer実装を登録するには、POF構成ファイルのContactInfoユーザー定義型に関するuser-type要素で、serializer要素内にIPofSerializerのクラス名を指定します。これを例18-12に示します。

例18-12 .NET型のIPofSerializer実装の登録

<?xml version="1.0"?>

<pof-config xmlns="http://schemas.tangosol.com/pof"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://schemas.tangosol.com/pof
   assembly://Coherence/Tangosol.Config/pof-config.xsd">
   <user-type-list>
   <!-- include all "standard" Coherence POF user types -->
      <include>assembly://Coherence/Tangosol.Config/coherence-pof-config.xml
      </include>
   <!-- include all application POF user types -->
      <user-type>
         <type-id>1001</type-id>
         <class-name>My.Example.ContactInfo, MyAssembly</class-name>
         <serializer>
            <class-name>My.Example.ContactInfoSerializer, MyAssembly</class-name>
         </serializer>
      </user-type>
   </user-type-list>
</pof-config>

同様に、Java型のContactInfoPofSerializer実装を登録できます。これを例18-13に示します。

例18-13 Java型のPofSerializer実装の登録

<?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 all "standard" Coherence POF user types -->
      <include>example-pof-config.xml</include>
   <!-- include all application POF user types -->
      <user-type>
         <type-id>1001</type-id>
         <class-name>com.mycompany.example.ContactInfo</class-name>
         <serializer>
            <class-name>com.mycompany.example.ContactInfoSerializer</class-name>
         </serializer>
      </user-type>
   </user-type-list>
</pof-config>

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

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

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

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

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

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

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

<?xml version="1.0"?>

<pof-config xmlns="http://schemas.tangosol.com/pof"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://schemas.tangosol.com/pof
   assembly://Coherence/Tangosol.Config/pof-config.xsd">
   ...
   <enable-references>true</enable-references>
</pof-config>

SimplePofContextクラスの使用時にオブジェクト参照を有効にするには、setReferenceEnabledメソッドをコールして、trueに設定します。例:

SimplePofContext ctx = new SimplePofContext();
ctx.IsReferenceEnabled = true;

注意:

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

18.8.2 循環構造のオブジェクトやネストされたオブジェクトへのPOFオブジェクトIDの登録

循環構造のオブジェクトやネストされたオブジェクトは、オブジェクトの作成時に手動でIDを登録する必要があります。これを行わないと、親を参照する子が、参照マップで親のIDを検出しません。オブジェクトのIDは、Tangosol.IO.Pof.IPofReader.RegisterIdentityメソッドを使用し、デシリアライズ・ルーチンでシリアライザから登録できます。

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

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

public class Customer
   {
      String m_name;
      Product m_product;
 
   public Customer(String name)
      {
      m_name = name;
      }
 
   public Customer(String name, Product product)
      {
      m_name = name;
      m_product = product;
      }
 
   public String getName()
      {
      return m_name;
      }
 
   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 : IPofSerializer
   {
   public void Serialize(IPofWriter pofWriter, object o)
      {
      var c = (Customer) o;
      pofWriter.WriteString(0, c.getName());
      pofWriter.WriteObject(1, c.getProduct());
      pofWriter.WriteRemainder(null);
   }
 
   public object Deserialize(IPofReader pofReader)
      {
      String name = pofReader.ReadString(0);
      var customer = new Customer(name);
 
      pofReader.RegisterIdentity(customer);
      customer.setProduct((Product) pofReader.ReadObject(1));
      pofReader.ReadRemainder();
      return customer;
      }
   }

18.9 POF注釈を使用したオブジェクトのシリアライズ

POF注釈は、オブジェクトにシリアライズやデシリアライズ・ルーチンの実装を自動化する方法を提供します。POF注釈は、IPofSerializerインタフェースの実装であるPofAnnotationSerializerクラスを使用してシリアライズまたはデシリアライズします。注釈は、IPortableObjectおよびIPofSerializerインタフェースのかわりに使用でき、オブジェクトをシリアライズ可能にするために必要な時間やコードの量を削減します。

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

18.9.1 POFシリアライズでのオブジェクトへの注釈付け

クラスとクラスのプロパティがPOFシリアライズ可能であることを示すために利用できる注釈は2つあります。

  • [Portable]: クラスをPOFシリアライズ可能とマークします。注釈は、クラス・レベルのみに使用でき、メンバーを含みません。

  • [PortableProperty]: プロパティ、アクセッサまたはメンバー変数をPOFシリアライズ化されたプロパティとしてマークします。注釈が付けられたメソッドは、アクセッサの表記法(GetSetIs)に従っている必要があります。メンバーを、POF索引や、シリアライズまたはデシリアライズの前後で実行するカスタム・コーデックの指定に使用できます。索引の値は省略可能で、自動的に割り当てられます。カスタム・コーデックを入力しない場合は、デフォルトのコーデックが使用されます。

次の例は、クラス、プロパティおよびメンバー変数への注釈付けを示しています。さらに、PortableProperty索引が明示的に指定されています。

[Portable]
public class Person
{
   [PortableProperty(0)]
   public string GetFirstName()
   {
      return m_firstName;
   }

   private String m_firstName;

   [PortableProperty(1)]
   public string LastName;
   {
      get; set;
   }

   [PortableProperty(2)]
   private int m_age;
}

18.9.2 POF注釈付きオブジェクトの登録

POF注釈付きオブジェクトは、pof-config.xmlファイルの<user-type>要素内で登録する必要があります。POFの構成要素の詳細は、『Oracle Coherence開発者ガイド』を参照してください。POF注釈付きオブジェクトは、IPortableObjectを実装していない場合はPofAnnotationSerializerシリアライザを使用し、Portableとして注釈が付けられます。ただし、このシリアライザは、オブジェクトが注釈付きかどうかと、ユーザー定義型に含める必要がないことを自動的に仮定します。次の例では、注釈付きPersonオブジェクトのユーザー定義型を登録します。

<?xml version='1.0'?>
<pof-config xmlns="http://schemas.tangosol.com/pof">
   <user-type-list>
    <!-- include all "standard" Coherence POF user types -->
      <include>assembly://Coherence/Tangosol.Config/coherence-pof-config.xml
      <!-- User types must be above 1000 -->
      <user-type>
         <type-id>1001</type-id>
         <class-name>My.Examples.Person, MyAssembly</class-name>
      </user-type>
</pof-config>

18.9.3 自動索引付けの有効化

POF注釈では、自動索引付けがサポートされており、明示的な索引値の割当てや管理の必要性を軽減されます。[PortableProperty]注釈を定義していれば、索引値は省略可能です。明示的に索引値を割り当てるプロパティによって、自動索引値が割り当てられることはありません。自動索引のアルゴリズムを表すと、次のようになります。

名前 明示的索引 決定された索引
c 1 1
a 省略 0
b 省略 2


注意:

自動索引では、現在、進化可能なクラスがサポートされていません。

自動索引付けを有効にするには、POF構成ファイルでユーザー定義型としてオブジェクトを登録するときにPofAnnotationSerializerシリアライザ・クラスを明示的に定義する必要があります。コンストラクタ内のautoIndexブール・パラメータで自動索引を有効にでき、必ずtrueに設定します。例:

<user-type>
   <type-id>1001</type-id>
   <class-name>com.examples.Person</class-name>
   <serializer>
      <class-name>Tangosol.IO.Pof.PofAnnotationSerializer, Coherence</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>

18.9.4 カスタム・コーデックの提供

コーデックによって、シリアライズまたはデシリアライズの前後でコードを実行できます。コーデックでは、IPofWriterおよびIPofReaderインタフェースを使用して、移植可能なプロパティをエンコードおよびデコードする方法を定義できます。コーデックは、一般に、デシリアライズ中に消失する可能性がある実用的な実装に使用します。または、オブジェクトをシリアライズする前にIPofWriterインタフェースで特定のメソッドを明示的にコールするために使用します。

コーデックを作成するには、ICodecインタフェースを実装するクラスを作成します。次の例は、LinkedList型の実用的な実装を定義するコーデックを示しています。

public class LinkedListCodec<T> : ICodec
{
   public object Decode(IPofReader reader, int index)
      {
         return reader.ReadCollection(index, (ICollection)new LinkedList<T>());
      }

   public void Encode(IPofWriter writer, int index, object value)
      {
         writer.WriteCollection(index, (ICollection)value);
      }
}

コーデックをプロパティに割り当てるには、コーデックを[PortableProperty]属性のメンバーとして入力します。コーデックを指定しない場合は、デフォルトのコーデック(DefaultCodec)が使用されます。次の例は、前述のLinkedListCodecコーデックの割当て方法を示しています。

[PortableProperty(typeof(LinkedListCodec<string>))]