この章では、C++クライアント作成時にPortable Object Format (POF)シリアライズ形式を使用する手順を説明します。
注意: このドキュメントでは、仕様に基づくクラス定義などの高度な概念も含め、CoherenceのC++オブジェクト・モデルに精通していると想定しています。これらのトピックの詳細は、第8章「CoherenceのC++オブジェクト・モデルの使用」を参照してください。 |
この章には次の項が含まれます:
C++クライアントを有効にしてCoherenceクラスタにC++ベースのオブジェクトを正しく格納するには、POF (Portable Object Format)という、プラットフォームに依存しないシリアライズ形式が必要です。POFを使用すると、値オブジェクトのプラットフォームおよび元の言語と関係ない方法で、値オブジェクトをバイナリ・ストリームにエンコードできます。このストリームは、類似するPOFベースのクラス定義を使用して、別の言語でデシリアライズできます。POFバイナリ・ストリームの詳細は、『Oracle Coherenceでのアプリケーションの開発』を参照してください。
Coherence C++ APIにはPOFシリアライズ可能クラスがいくつか用意されていますが、カスタムのデータ型ではこの章で説明するようにシリアライズのサポートが必要です。
次の型はPOFで内部的にサポートされているので、ユーザー側で特別な処理をする必要はありません。
String
Integer16 .. Integer64
Float32、Float64
プリミティブの配列<>
ObjectArray
Boolean
Octet
Character16
また、次の一般的なインタフェースを実装するクラスでは自動POFシリアライズが可能です。
Map
Collection
Exception
Coherence C++ APIが備えているシリアライズ形式は1つのみ(POF)ですが、クラスをシリアライズ可能にするAPIは多数用意されています。どのようなアプローチを採用しても、最終的には同じバイナリPOF形式が生成されます。クラスをシリアライズ可能にするには、次のアプローチを利用できます。
Managed<T>
アダプタ・テンプレートを使用して、外部の自由関数シリアライザを追加します。詳細は、「Managed<T>(自由関数シリアライズ)」を参照してください。
データ・オブジェクトを変更してObject
を拡張し、PortableObject
インタフェースを実装して、オブジェクトで自己シリアライズができるようにします。詳細は、「PortableObject (自己シリアライズ)」を参照してください。
データ・オブジェクトを変更してObject
を拡張し、PofSerializer
クラスを作成して外部シリアライズを実行します。詳細は、「PofSerializer (外部シリアライズ)」を参照してください。
表10-1は、それぞれのアプローチの要件と制限をいくつか示しています。
表10-1 シリアライズの各オプションの要件と制限
アプローチ | データ・オブジェクトのCoherenceヘッダー | Objectからの派生の必要性 | constデータ・メンバーのサポート | 外部シリアライズ・ルーチン | 引数がないコンストラクタの必要性 |
---|---|---|---|---|---|
Managed<T> |
いいえ |
いいえ |
はい |
はい |
はい |
PortableObject |
はい |
はい |
いいえ |
いいえ |
はい |
PofSerializer |
はい |
はい |
はい |
はい |
いいえ |
これらのアプローチにはすべて、次のような共通点があります。
データ・アイテムをPOFにエンコードできるようにするシリアライズ・ルーチンを実装する必要があります。
データ・オブジェクトのフィールドを特定するには、数値インデックスを使用します。
データ・オブジェクト・クラスとシリアライズのメカニズムをCoherenceに登録する必要があります。
キャッシュ・キーとして使用するデータ・オブジェクトは、等価比較とハッシュをサポートしている必要があります。
既存のデータ・オブジェクト・クラスのほとんどでは、Managed<T>
を使用すると、最も容易にCoherence for C++に統合できます。
非管理クラスがManaged<T>
と互換性を持つようにするには、そのクラスに次のような特性があることが必要です。
パラメータのないコンストラクタ(publicまたはprotected): CustomType::CustomType()
コピー・コンストラクタ(publicまたはprotected): CustomType::CustomType(const CustomType&)
等価比較の演算子: ブール演算子==(const CustomType&, const CustomType&)
std::ostream
出力関数: std::ostream&
operator
<<(std::ostream&
, const
CustomType&)
ハッシュ関数: size_t hash_value
(const CustomType&)
次の例は、簡単なAddress
クラスを示しています。このクラスは、Coherenceの直接の知識は不要ですが、Managed<T>
テンプレートでの使用に適しています。
注意: 見やすさを考慮して、ここではクラス定義の例を宣言の中に記述しています。 |
例10-1 非管理クラス
#include <iostream> #include <string> using namespace std; class Address { public: Address(const std::string& sCity, const std::string& sState, int nZip) : m_sCity(sCity), m_sState(sState), m_nZip(nZip) {} Address(const Address& that) // required by Managed<T> : m_sCity(that.m_sCity), m_sState(that.m_sState), m_nZip(that.m_nZip) {} protected: Address() // required by Managed<T> : m_nZip(0) {} public: std::string getCity() const {return m_sCity;} std::string getState() const {return m_sState;} int getZip() const {return m_nZip;} private: const std::string m_sCity; const std::string m_sState; const int m_nZip; }; bool operator==(const Address& addra, const Address& addrb) // required by Managed<T> { return addra.getZip() == addrb.getZip() && addra.getState() == addrb.getState() && addra.getCity() == addrb.getCity(); } std::ostream& operator<<(std::ostream& out, const Address& addr) // required by Managed<T> { out << addr.getCity() << ", " << addr.getState() << " " << addr.getZip(); return out; } size_t hash_value(const Address& addr) // required by Managed<T> { return (size_t) addr.getZip(); }
Managed<T>
と組み合せたこの簡単なクラス定義は、真の管理オブジェクトとなり、Coherence C++ APIで使用できるようになります。この定義のみでは、まだシリアライズに対処できません。例10-2では、シリアライズのサポートが追加されています。
例10-2 シリアライズを使用した管理クラス
#include "coherence/io/pof/SystemPofContext.hpp" #include "Address.hpp" using namespace coherence::io::pof; COH_REGISTER_MANAGED_CLASS(1234, Address); // type ID registration—this must // appear in the .cpp not the .hpp template<> void serialize<Address>(PofWriter::Handle hOut, const Address& addr) { hOut->writeString(0, addr.getCity()); hOut->writeString(1, addr.getState()); hOut->writeInt32 (2, addr.getZip()); } template<> Address deserialize<Address>(PofReader::Handle hIn) { std::string sCity = hIn->readString(0); std::string sState = hIn->readString(1); int nZip = hIn->readInt32 (2); return Address(sCity, sState, nZip); }
注意: このシリアライズ・ルーチンでは、Coherenceの知識が必要です。ただし、クラス定義ファイルの中に記述する必要はありません。独立したソース・ファイルに記述してもかまいません。最終的なアプリケーションでそのファイルをリンクすると、ルーチンとして正常に機能します。 |
例10-3は、前述の例を使用して、Address
クラスのインスタンスをManaged<T>
でラップしてManaged<Address>
とし、Coherence APIに提供することを示しています。
例10-3 Managed<T>でラップしたクラスのインスタンス
// construct the non-managed version as usual Address office("Redwood Shores", "CA", 94065); // the managed version can be initialized from the non-managed version // the result is a new object, which does not reference the original Managed<Address>::View vOffice = Managed<Address>::create(office); String::View vKey = "Oracle"; // the managed version is suitable for use with caches hCache->put(vKey, vAddr); vOffice = cast<Managed<Address>::View>(hCache->get(vKey)); // the non-managed class's public methods/fields remain accessible assert(vOffice->getCity() == office.getCity()); assert(vOffice->getState() == office.getState()); assert(vOffice->getZip() == office.getZip()); // conversion back to the non-managed type may be performed using the // non-managed class's copy constructor. Address officeOut = *vOffice;
PortableObject
インタフェースは、概念の面から見ると、オブジェクトのシリアライズ方法をそのオブジェクト自身で制御できるようにするjava.io.Externalizable
に類似しています。coherence::lang::Object
を拡張したクラスであれば、coherence::io::pof::PortableObject
インタフェースを自由に実装してシリアライズのサポートを追加できます。このクラスはObjectを拡張したものであることが必要
で、拡張後のクラスのライフサイクルはこのObjectで規定します。
例10-4では、前述のAddress
の例を管理クラスとして書き換え、PortableObject
インタフェースを実装できます。ここでは、このクラスの定義の中でCoherenceオブジェクト・モデル全体を扱うようにしています。たとえば、データ・メンバーに対してstd::string
ではなく、coherence::lang::String
を使用します。
例10-4 PortableObjectを実装する管理クラス
#include "coherence/lang.ns" #include "coherence/io/pof/PofReader.hpp" #include "coherence/io/pof/PofWriter.hpp" #include "coherence/io/pof/PortableObject.hpp" #include "coherence/io/pof/SystemPofContext.hpp" using namespace coherence::lang; using coherence::io::pof::PofReader; using coherence::io::pof::PofWriter; using coherence::io::pof::PortableObject; class Address : public cloneable_spec<Address, extends<Object>, implements<PortableObject> > { friend class factory<Address>; protected: // constructors Address(String::View vsCity, String::View vsState, int32_t nZip) : m_vsCity(self(), vsCity), m_vsState(self(), vsState), m_nZip(nZip) {} Address(const Address& that) : super(that), m_vsCity(self(), that.m_vsCity), m_vsState(self(), that.m_vsState), m_nZip(that.m_nZip) {} Address() // required by PortableObject : m_vsCity(self()), m_vsState(self()), m_nZip(0) {} public: // Address interface virtual String::View getCity() const {return m_vsCity;} virtual String::View getState() const {return m_vsState;} virtual int32_t getZip() const {return m_nZip;} public: // PortableObject interface virtual void writeExternal(PofWriter::Handle hOut) const { hOut->writeString(0, getCity()); hOut->writeString(1, getState()); hOut->writeInt32 (2, getZip()); } virtual void readExternal(PofReader::Handle hIn) { initialize(m_vsCity, hIn->readString(0)); initialize(m_vsState, hIn->readString(1)); m_nZip = hIn->readInt32 (2); } public: // Objectinterface virtual bool equals(Object::View that) const { if (instanceof<Address::View>(that)) { Address::View vThat = cast<Address::View>(that); return getZip() == vThat->getZip() && Object::equals(getState(), vThat->getState()) && Object::equals(getCity(), vThat->getCity()); } return false; } virtual size32_t hashCode() const { return (size32_t) m_nZip; } virtual void toStream(std::ostream& out) const { out << getCity() << ", " << getState() << " " << getZip(); } private: FinalView<String> m_vsCity; FinalView<String> m_vsState; int32_t m_nZip; }; COH_REGISTER_PORTABLE_CLASS(1234, Address); // type ID registration—this must // appear in the .cpp not the .hpp
例10-5は、Address
の管理バリアントを示しています。このバリアントは、Managed<T>
アダプタの使用を必要とせず、Coherence APIで直接使用できます。
例10-5 Managed<T>を使用しない管理クラス
Address::View vAddr = Address::create("Redwood Shores", "CA", 94065); String::View vKey = "Oracle"; hCache->put(vKey, vAddr); Address::View vOffice = cast<Address::View>(hCache->get(vKey));
Coherenceオブジェクト・モデルを利用してデータ・オブジェクトを記述することにしているアプリケーションでは、PortableObject
を使用したシリアライズが最適です。PortableObjectの短所として、constデータ・メンバーのサポートが容易ではないという点があります。これは、コンストラクタの実行後にreadExternal
メソッドがコールされ、その時点でconstデータ・メンバーの値を割り当てる必要があるためです。
3番目のシリアライズ・オプションも最低レベルのものです。PofSerializer
は、自身以外のクラスにシリアライズ・ロジックを提供するクラスです。たとえば、前述の管理Address
クラスの非PortableObject
バージョンをシリアライズできるAddressSerializer
を記述します。前述の2つのアプローチでは、これらは明示的に作成していたのではなく、PofSerializer
に委任されていた保護の下で自動的に作成されていました。通常は、Managed<T>
とPortableObject
のいずれかのアプローチで十分であるため、このアプローチを採用する必要はありません。このアプローチが効果的なのは、constデータ・メンバーを持つ管理オブジェクトを扱う場合です。例10-6では、非PortableObject
バージョンの管理Address
を検討します。
例10-6 非PortableObjectバージョンの管理クラス
#include "coherence/lang.ns" using namespace coherence::lang; class Address : public cloneable_spec<Address> // extends<Object> is implied { friend class factory<Address>; protected: // constructors Address(String::View vsCity, String::View vsState, int32_t nZip) : m_vsCity(self(), vsCity), m_vsState(self(), vsState), m_nZip(nZip) {} Address(const Address& that) : super(that), m_vsCity(self(), that.getCity()), m_vsState(self(), that.getState()), m_nZip(that.getZip()) {} public: // Address interface virtual String::View getCity() const {return m_vsCity;} virtual String::View getState() const {return m_vsState;} virtual int32_t getZip() const {return m_nZip;} public: // Objectinterface virtual bool equals(Object::View that) const { if (instanceof<Address::View>(that)) { Address::View vThat = cast<Address::View>(that); return getZip() == vThat->getZip() && Object::equals(getState(), vThat->getState()) && Object::equals(getCity(), vThat->getCity()); } return false; } virtual size32_t hashCode() const { return (size32_t) m_nZip; } virtual void toStream(std::ostream& out) const { out << getCity() << ", " << getState() << " " << getZip(); } private: const MemberView<String> m_vsCity; const MemberView<String> m_vsState; const int32_t m_nZip; };
このバージョンはconst
データ・メンバーを使用しているため、PortableObject
には適していません。例10-7は、Address
インスタンスのシリアライズを担当するものとして登録される外部クラスAddressSerializer
を示しています。
例10-7 シリアライズを担当する外部クラス
#include "coherence/lang.ns" #include "coherence/io/pof/PofReader.hpp" #include "coherence/io/pof/PofWriter.hpp" #include "coherence/io/pof/PortableObject.hpp" #include "coherence/io/pof/PofSerializer.hpp" #include "coherence/io/pof/SystemPofContext.hpp" #include "Address.hpp" using namespace coherence::lang; using coherence::io::pof::PofReader; using coherence::io::pof::PofWriter; using coherence::io::pof::PofSerializer; class AddressSerializer : public class_spec<AddressSerializer, extends<Object>, implements<PofSerializer> > { friend class factory<AddressSerializer>; protected: AddressSerializer(); public: // PofSerializer interface virtual void serialize(PofWriter::Handle hOut, Object::View v) const { Address::View vAddr = cast<Address::View>(v); hOut->writeString(0, vAddr->getCity()); hOut->writeString(1, vAddr->getState()); hOut->writeInt32 (2, vAddr->getZip()); hOut->writeRemainder(NULL); } virtual Object::Holder deserialize(PofReader::Handle hIn) const { String::View vsCity = hIn->readString(0); String::View vsState = hIn->readString(1); int32_t nZip = hIn->readInt32 (2); hIn->readRemainder(); return Address::create(vsCity, vsState, nZip); } }; COH_REGISTER_POF_SERIALIZER(1234, TypedBarrenClass<Address>::create(),AddressSerializer::create()); // This must appear in the .cpp not the .hpp
Address
の使用方法は、次のようにこれまでと同じです。
Address::View vAddr = Address::create("Redwood Shores", "CA", 94065); String::View vKey = "Oracle"; hCache->put(vKey, vAddr); Address::View vOffice = cast<Address::View>(hCache->get(vKey));
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コンテキストを作成するときにsetReferenceEnabled
を使用して有効にする必要があります。例:
SystemPofContext::Handle hCtx = SystemPofContext::getInstance(); hCtx->setReferenceEnabled(true);
循環構造のオブジェクトやネストされたオブジェクトは、オブジェクトの作成時に手動でIDを登録する必要があります。これを行わないと、親を参照する子が、参照マップで親のIDを検出しません。オブジェクトのIDは、PofReader.registerIdentity
メソッドを使用し、デシリアライズ・ルーチンでシリアライザから登録できます。
次の例では、循環参照を含んだ2つのオブジェクト(Customer
およびProduct
)と、Customer
オブジェクトのIDを登録するシリアライザ実装を示しています。
Customer
オブジェクトの定義は次のとおりです。
class Customer : public class_spec<Customer, extends<Object> > { friend class factory<Customer>; protected: Customer() : m_vsName(self(), String::null_string), m_vProduct(self(), NULL) { } Customer(String::View vsName) : m_vsName(self(), vsName), m_vProduct(self(), NULL) { } Customer(String::View vsName, Product::View vProduct) : m_vsName(self(), vsName), m_vProduct(self(), vProduct) { } public: String::View getName() const { return m_vsName; } void setName(String::View vsName) { m_vsName = vsName; } Product::View getProduct() const { return m_vProduct; } void setProduct(Product::View vProduct) { m_vProduct = vProduct; } private: MemberView<String> m_vsName; MemberView<Product> m_vProduct; };
Product
オブジェクトの定義は次のとおりです。
class Product : public class_spec<Product, extends<Object> > { friend class factory<Product>; protected: Product() : m_vCustomer(self(), NULL) { } Product(Customer::View vCustomer) : m_vCustomer(self(), vCustomer) { } public: Customer::View getCustomer() const { return m_vCustomer; } void setCustomer(Customer::View vCustomer) { m_vCustomer= vCustomer; } private: MemberView<Customer> m_vCustomer; };
デシリアライズの間にIDを登録するシリアライザ実装の定義は次のとおりです。
class CustomerSerializer
: public class_spec<CustomerSerializer,
extends<Object>,
implements<PofSerializer> >
{
friend class factory<CustomerSerializer>;
public:
void serialize(PofWriter::Handle hOut, Object::View v) const
{
Customer::View vCustomer = cast<Customer::View>(v);
hOut->writeString(0, vCustomer->getName());
hOut->writeObject(1, vCustomer->getProduct());
hOut->writeRemainder(NULL);
}
Object::Holder deserialize(PofReader::Handle hIn) const
{
String::View vsName = cast<String::View>(hIn->readString(0));
Customer::Holder ohCustomer = Customer::create(vsName);
hIn->registerIdentity(ohCustomer);
ohCustomer->setProduct(cast<Product::View>(hIn->readObject(1)));
hIn->readRemainder();
return ohCustomer;
}
};
シリアライズ可能にすることに加え、各クラスには数値型のIDを関連付ける必要があります。これらのIDはクラスタ全体で既知の状態になっています。クラスタでは、POFユーザー定義型の構成要素を使用して、IDとクラスとのマッピングを構成します。C++では、IDの登録の形式でクラス定義の中にこのマッピングを埋め込みます。これは、クラスの .cpp
ソース・ファイルに記述します。
この登録の手法は、次のようにシリアライズのアプローチごとに少々異なります。
COH_REGISTER_MANAGED_CLASS(ID, TYPE)
: Managed<T>
による方法の場合
COH_REGISTER_PORTABLE_CLASS(ID, TYPE)
: PortableObject
による方法の場合
COH_REGISTER_POF_SERIALIZER(ID, CLASS, SERIALIZER)
: PofSerializer
による方法の場合
これらの登録の例は、前述の例に記載されています。
注意: 登録を記述するファイルは実装ファイル(.cpp )のみとします。POF構成ファイルは、オブジェクトをシリアライズおよびデシリアライズするノードでのみ必要です。 |
POFの使用によって、並列のJava実装を必要とせずに、キーおよび値オブジェクトをクラスタ内に格納できます。これは、基本的なgetとputベースの操作を実行する場合に適しています。さらに、PofExtractor
とPofUpdater
APIにより、Coherenceの非プリミティブ・タイプを使用するときの柔軟性が向上します。多くの拡張クライアントの場合、グリッド内に対応するJavaクラスは不要です。POFエクストラクタとPOFアップデータはバイナリをナビゲートできるため、キーと値全体をオブジェクト形式にデシリアライズしなくても済みます。これは、索引付けする値をPOFエクストラクタを使用してプルするだけで索引付けできることを意味します。
並列のJava実装の組込みが必要になる状況
Javaベースのキャッシュ・サーバーが、データ・オブジェクトのシリアライズ表現を保持するだけでなく、データ・オブジェクトと直接対話する必要がある場合は、並列のJava実装が必要です。たとえば、キャッシュ・ストアを使用するときJavaクラスは必要です。この場合、キーと値のデシリアライズ・バージョンがキャッシュ・ストアに渡され、バックエンドに書き込まれます。さらに、オブジェクトへの直接アクセスが必要な場合、問合せ、フィルタ、入力プロセッサおよびアグリゲータはJava実装が必要です。
Java実装が必要な場合は、実装はキャッシュ・サーバーにある必要があります。JavaバージョンのPOFでシリアライズ可能にする方法は前述の例とほぼ同じです。詳細は、PortableObject
およびPofSerializer
を参照してください。これらのAPIは、C++の3つの方法すべてと互換性があります。
キーの関連付けチェックの遅延
キー・クラスは、クラスタ側Java実装を必要としません。これはKeyAssociation
を使用してデータのアフィニティを指定している場合でも同様です。キー・クラスは、クライアント側でチェックされ、修飾されたバイナリがクラスタによって作成および使用されます。ただし、キーの関連付けをJavaキー・クラスに依存している既存のクライアント実装は、Javaキー・クラスの使用を強制するためにdefer-key-association-check
パラメータを設定する必要があります。キーの関連付けを使用する既存クライアント・アプリケーションで、クライアント側のキー・バイナリを利用する場合は、getAssociatedKey()
実装を既存のJavaクラスから対応するクライアント・クラスに移植する必要があります。
キーの関連付け処理を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キー・クラス実装は、キーの関連付けを使用していない場合でも、クラスタに存在する必要があります。 |
Managed<T>
とPortableObject
は、いずれもバックグラウンドでPofSerializer
を使用してシリアライズを実行します。これらのアプローチのそれぞれで独自のオーバーヘッドが発生します。たとえば、Managed<T>
によるアプローチでは、デシリアライズの過程で、一時バージョンのデータ・オブジェクトが非管理形式で作成されます。PortableObject
の場合は、constデータ・メンバーに対するサポートがないことから、constデータ・メンバーに対して可能な最適化が回避されるために、余分なコストが発生する可能性があります。全体としてはパフォーマンスの差は無視できますが、可能なかぎり最大のパフォーマンス実現を追求する場合は、PofSerializer
を直接使用することも検討に値します。
POF注釈は、オブジェクトにシリアライズやデシリアライズ・ルーチンの実装を自動化する方法を提供します。POF注釈は、PofSerializer
インタフェースの実装であるPofAnnotationSerializer
クラスを使用してシリアライズまたはデシリアライズします。注釈は、Managed<T>
アダプタ、PortableObject
インタフェースおよびPofSerializer
インタフェースのかわりに使用でき、オブジェクトをシリアライズ可能にするために必要な時間やコードの量を削減します。
この項には、次のトピックが含まれます:
クラスとクラスのメソッドがPOFシリアライズ可能であることを示すために利用できる注釈は2つあります。
Portable
- クラスをPOFシリアライズ可能とマークします。注釈は、クラス・レベルのみに使用でき、メンバーを含みません。
PortableProperty
- メソッド・アクセッサをPOFシリアライズ化されたプロパティとしてマークします。注釈が付けられたメソッドは、アクセッサの表記法(get
、set
、is
)に従っている必要があります。メンバーを、POF索引や、シリアライズまたはデシリアライズの前後で実行するカスタム・コーデックの指定に使用できます。索引の値は省略可能で、自動的に割り当てられます。カスタム・コーデックを入力しない場合は、デフォルトのコーデックが使用されます。
次の例は、クラスとメソッドへの注釈付けと、プロパティ索引値の明示的な割当てを示しています。クラスはシステム・クラス・ローダーCOH_REGISTER_CLASS
とともに登録する必要があります。
class Person : public class_spec<Person> { friend class factory<Person>; Public: String::View getFirstName() const { return m_vsFirstName; } void setFirstName(String::View vsFirstName) { m_vsFirstName = vsFirstName; } private: String m_firstName; MemberView<String> m_vsFirstName; MemberView<String> m_vsLastName; int32_t m_nAge; public: static const int32_t FIRST_NAME = 0; static const int32_t LAST_NAME = 1; static const int32_t AGE = 2; }; COH_REGISTER_CLASS(TypedClass<Person>::create() ->annotate(Portable::create()) ->declare(COH_PROPERTY(Person, FirstName, String::View) ->annotate(PortableProperty::create(Person::FIRST_NAME))) ->declare(COH_PROPERTY(Person, LastName, String::View) ->annotate(PortableProperty::create(Person::LAST_NAME))) ->declare(COH_PROPERTY(Person, Age, BoxHandle<const Integer32>) ->annotate(PortableProperty::create(Person::AGE))) );
POF注釈付きオブジェクトは、COH_REGISTER_POF_ANNOTATED_CLASS
マクロを使用してユーザー定義型として登録する必要があります。次の例では、注釈付きPerson
オブジェクトのユーザー定義型を登録します。
COH_REGISTER_POF_ANNOTATED_CLASS(1001, Person);
POF注釈では、自動索引付けがサポートされており、明示的な索引値の割当てや管理の必要性を軽減されます。PortableProperty
注釈を定義していれば、索引値は省略可能です。明示的に索引値を割り当てるプロパティによって、自動索引値が割り当てられることはありません。自動索引のアルゴリズムを表すと、次のようになります。
名前 | 明示的索引 | 決定された索引 |
---|---|---|
c | 1 | 1 |
a | 省略 | 0 |
b | 省略 | 2 |
注意: 自動索引では、現在、進化可能なクラスがサポートされていません。 |
自動索引付けを有効にするには、ユーザー定義型を登録するときにCOH_REGISTER_POF_ANNOTATED_CLASS_AI
プリプロセッサを使用します。次の例では、自動索引付けを使用する注釈付きPerson
オブジェクトのユーザー定義型を登録します。
COH_REGISTER_POF_ANNOTATED_CLASS_AI(1001, Person);
コーデックによって、シリアライズまたはデシリアライズの前後でコードを実行できます。コーデックでは、PofWriter
およびPofReader
インタフェースを使用して、移植可能なプロパティをエンコードおよびデコードする方法を定義できます。コーデックは、一般に、デシリアライズ中に消失する可能性がある実用的な実装に使用します。または、オブジェクトをシリアライズする前にPofWriter
インタフェースで特定のメソッドを明示的にコールするために使用します。
コーデックを作成するには、Codec
インタフェースを実装するクラスを作成します。次の例は、リンクされたリスト型の実用的な実装を定義するコーデックを示しています。
class LinkedListCodec : public class_spec<LinkedListCodec, extends<Object>, implements<Codec> > { friend class factory<LinkedListCodec>; public: void encode(PofWriter::Handle hOut, int32_t nIndex, Object::View ovValue) const { hOut->writeCollection(nIndex, cast<Collection::View>(ovValue)); } Object::Holder decode(PofReader::Handle hIn, int32_t nIndex) const { LinkedList::Handle hLinkeList = LinkedList::create(); return hIn->readCollection(nIndex, hLinkeList); } }; COH_REGISTER_TYPED_CLASS(LinkedListCodec);
コーデックをプロパティに割り当てるには、コーデックをPortableProperty
注釈のメンバーとして入力します。コーデックを指定しない場合は、デフォルトのコーデック(DefaultCodec
)が使用されます。次の例は、前述のLinkedListCodec
コーデックの割当て方法を示しています。
COH_REGISTER_CLASS(TypedClass<Person>::create() ->annotate(Portable::create()) ->declare(COH_PROPERTY(Person, FirstName, String::View) ->annotate(PortableProperty::create(Person::FIRST_NAME))) ->declare(COH_PROPERTY(Person, LastName, String::View) ->annotate(PortableProperty::create(Person::LAST_NAME))) ->declare(COH_PROPERTY(Person, Age, BoxHandle<const Integer32>) ->annotate(PortableProperty::create(Person::ALIASES, SystemClassLoader::getInstance()->loadByType(typeid(LinkedListCodec)) ))) );