Using Automatic PDX Serialization
You can allow your C++ client applications to automatically PDX serialize and deserialize domain objects without having to add any extra code by using the provided pdxautoserializer
command line tool.
When using the C++ client API, you can automatically serialize and deserialize domain objects without making any code changes to those objects or having to implement a PdxSerializer
or PdxSerializable
interface and their related fromData
and toData
methods. The pdxautoserializer
command-line utility allows you to generate C++ code that will serialize your domain objects in the PDX format for you.
How to Use Automatic PDX Serialization
The procedure below uses the following sample class:
class PortfolioPdx
{
private:
int32_t id;
char* pkid;
PositionPdxPtr position1;
PositionPdxPtr position2;
CacheableHashMapPtr positions;
char** names;
int8_t* newVal;
CacheableDatePtr creationDate;
int8_t* arrayNull;
int8_t* arrayZeroSize;
public:
// CTOR
// DTORS
// Other Methods declarations
For each domain class you provide, all fields are considered for serialization except those defined as static or transient and those you explicitly exclude using macros.
Inherit your class from
apache::geode::client::PdxSerializable
.class PortfolioPdx : public PdxSerializable
Add the following method declarations in the public part of the class.
const char* getClassName() const; virtual void toData(apache::geode::client::PdxWriterPtr pw); virtual void fromData(apache::geode::client::PdxReaderPtr pr); static PdxSerializable* createDeserializable();
In your pre-build environment (for example in your makefiles), call
pdxautoserializer
as follows:<GFCPP>/bin/pdxautoserializer.exe --outDir=<location to generate files> <SOURCE_DIR>/PortfolioPdx.hpp
Include the generated file in your project and compile.
The following is an example of a generated file:
#include "PortfolioPdx.hpp"
#include <geode/PdxWriter.hpp>
#include <geode/PdxReader.hpp>
#include <geode/PdxAutoSerializer.hpp>
namespace testobject
{
void PortfolioPdx::toData(apache::geode::client::PdxWriterPtr var)
{
apache::geode::client::PdxAutoSerializable::writePdxObject(var, "id", id);
apache::geode::client::PdxAutoSerializable::writePdxObject(var, "pkid", pkid);
apache::geode::client::PdxAutoSerializable::writePdxObject(var, "position1", position1);
apache::geode::client::PdxAutoSerializable::writePdxObject(var, "position2", position2);
apache::geode::client::PdxAutoSerializable::writePdxObject(var, "positions", positions);
apache::geode::client::PdxAutoSerializable::writePdxObject(var, "status", status);
apache::geode::client::PdxAutoSerializable::writePdxObject(var, "creationDate", creationDate);
}
void PortfolioPdx::fromData(PdxReaderPtr var)
{
apache::geode::client::PdxAutoSerializable::readPdxObject(var, "id", id);
apache::geode::client::PdxAutoSerializable::readPdxObject(var, "pkid", pkid);
apache::geode::client::PdxAutoSerializable::readPdxObject(var, "position1", position1);
apache::geode::client::PdxAutoSerializable::readPdxObject(var, "position2", position2);
apache::geode::client::PdxAutoSerializable::readPdxObject(var, "positions", positions);
apache::geode::client::PdxAutoSerializable::readPdxObject(var, "status", status);
apache::geode::client::PdxAutoSerializable::readPdxObject(var, "creationDate", creationDate);
}
const char* PortfolioPdx::getClassName() const
{
return "PortfolioPdx";
}
}
Handling Arrays
Define the following macro in your header file:
#define GFARRAYSIZE(x)
Assuming that the following is the class member of type array:
int8_t* newVal;
Then define a new variable which sets the length of the array:
int32_t newValSize;
Tag the new variable with the
GFARRAYSIZE
macro as follows:GFARRAYSIZE(newVal) int32_t newValSize;
Using a Single Variable as Length for Multiple Arrays
You can use the GFARRAYSIZES to have single length for multiple arrays.
Define the GFARRAYSIZES macro as follows:
#define GFARRAYSIZES(x)
The following is an example usage:
class ArrayOfSizes?
{
public:
int32_t* array1;
int32_t* array2;
int32_t* array3;
int32_t* array4;
int32_t* array5;
GFARRAYSIZE(array1) int32_t singleSize;
GFARRAYSIZES("array2,array3,array4,array5") int32_t SingleSizeToMultipleArrays?;
};
Excluding Member Variables from Serialization
Define the following macro in your header file:
#define GFEXCLUDE
Tag your member variable with this macro:
GFEXCLUDE char* type;
Marking Identity Fields
Identity fields are used when comparing objects using the hashCode
and equals
methods.
Define the following macro in your header file.
#define GFID(x)
Assuming that the following is the class member you want to use as IdentityField:
int8_t* newVal;
Tag the member with the GFID macro as follows:
GFID(newVal)int8_t* newVal;
Ignoring User Defined Keywords
You might have certain user defined keywords after the class name. Current C++ grammar does not support this. If you have some keywords user will have to ignore them by using the GFIGNORE
macro.
For example, consider the following class definition:
#ifdef _WIN32
#ifdef BUILD_TESTOBJECT
#define TESTOBJECT_EXPORT _GEODE_LIBEXP
#else
#define TESTOBJECT_EXPORT _GEODE_LIBIMP
#endif
#else
#define TESTOBJECT_EXPORT
#endif
namespace PdxAutoTests {
class TESTOBJECT_EXPORT PdxAutoMegaType : public PdxSerializable {
}
Currently, the pdxautoserializer
tool will fail to recognize TESTOBJECT_EXPORT
. Change your class by adding the GFIGNORE
macro as follows:
#ifdef _WIN32
#ifdef BUILD_TESTOBJECT
#define TESTOBJECT_EXPORT _GEODE_LIBEXP
#else
#define TESTOBJECT_EXPORT _GEODE_LIBIMP
#endif
#else
#define TESTOBJECT_EXPORT
#endif
using namespace apache::geode::client;
#define GFIGNORE(X) X
#define GFID
namespace PdxAutoTests {
class GFIGNORE(TESTOBJECT_EXPORT) PdxAutoMegaType : public PdxSerializable {
Additional Usage Information for the pdxautoserializer Tool
The pdxautoserializer
tool takes classes as input and generates code that will serialize the class into the PDX format for you.
The pdxautoserializer
tool is located in $GEODE/bin
where $GEODE
corresponds to the installation location of the client.
Some additional notes about using the pdxautoserializer
tool:
- Any const type in the class members are ignored by the
pdxserializer
tool. - Generated files will have namespace in the file name.
To view the command-line help for the tool, type:
prompt> pdxautoserializer.exe --help
Help returns the following syntax and usage information:
Usage: pdxautoserializer.exe [OPTIONS] <resources e.g. header> ...
Resource name should be the path to the header containing the classes to be
auto-serialized.
[OPTIONS] may be one of those given below.
SINGLE denotes that the option should be specified only once.
MULTIPLE denotes that the option can be specified more than once.
OPTIONAL denotes that the option may be skipped in which case the default
for that shall be chosen.
--className=VALUE Name of the class for which to generate auto-serialization code (MULTIPLE,OPTIONAL)
--classNameStr=VALUE Name of the class in string (MULTIPLE,OPTIONAL)
--help This help message.
--outDir The output directory of the generated files (SINGLE,OPTIONAL)
--suffix The suffix of the generated filenames -- default is 'Serializable' (SINGLE,OPTIONAL)
--usage This usage message.
Examples:
pdxautoserializer -outDir=<DIR NAME> <RESOURCE>
pdxautoserializer -outDir=<DIR NAME> --className=<CLASSNAME1> --className=<CLASSNAME2> <RESOURCE>
pdxautoserializer -outDir=<DIR NAME> --classNameStr=<CLASSNAME1:User defined String> --classNameStr=<CLASSNAME:User defined String> <RESOURCE>
Helper Macros to be defined in Input Header File :
GFINCLUDE for including a specific member for serialization
GFEXCLUDE for excluding a specific member for serialization
GFID for considering a member as Identify Field
GFARRAYSIZE for specifying a array length member
GFIGNORE for ignoring certain keywords
For more details refer to documentation on this utility.
Generating Automatic Code for a Single Class
Many times there are multiple classes in a single header file. For example:
#ifndef HEADER_HEADER
#define HEADER_HEADER
class class1{
};
class class2{
};
class class3 : public PdxSerializable{
};
#endif
If you want to generate code for only one of the classes, then use the --className
option. For example, if you only want to generate code for class3, then you would use the following command:
pdxautoserializer --outDir=<outDir> --className=class3
Choosing Your Own Suffix to Identify the Generated Files.
The pdxserializer
tool also provides the option to choose your own suffix for the generated C++ files. This can help you write less code in your makefiles. Here’s an example command:
pdxautoserializer --outDir=<outDir> --className=CharTypes --suffix="generated"
Example of Using PDX Serialization in Your Application
CacheFactoryPtr cacheFactory = CacheFactory::createCacheFactory();
// Create a cache with the "clientPdxRemoteQuery.xml" Cache XML file.
CachePtr cachePtr = cacheFactory->set("cache-xml-file", "XMLs\\clientPdxRemoteQuery.xml")
->create();
LOGINFO("Created the Cache");
// Get the example Region from the Cache which is declared in the Cache XML file.
RegionPtr regionPtr = cachePtr->getRegion( "Portfolios");
LOGINFO( "Obtained the Region from the Cache");
// Register our Serializable/Cacheable Query objects, viz. PortfolioPdx and PositionPdx.
Serializable::registerPdxType(PortfolioPdx::createDeserializable);
PortfolioPdxPtr port1Ptr(new PortfolioPdx(1 /*ID*/, 10 /*size*/));
PortfolioPdxPtr port2Ptr(new PortfolioPdx(2 /*ID*/, 20 /*size*/));
PortfolioPdxPtr port3Ptr(new PortfolioPdx(3 /*ID*/, 30 /*size*/));
regionPtr->put("Key1", port1Ptr);
regionPtr->put("Key2", port2Ptr);
regionPtr->put("Key3", port3Ptr);
// Get the QueryService from the Cache.
QueryServicePtr qrySvcPtr = cachePtr->getQueryService( "examplePool");
LOGINFO( "Got the QueryService from the Cache");
// Execute a Query which returns a ResultSet.
QueryPtr qryPtr = qrySvcPtr->newQuery("SELECT DISTINCT * FROM /Portfolios");
SelectResultsPtr resultsPtr = qryPtr->execute();
LOGINFO( "ResultSet Query returned %d rows", resultsPtr->size());