Skip to content

Commit

Permalink
Backported fixes from master(hazelcast#37)
Browse files Browse the repository at this point in the history
CHECK_NULL in SerializationService header moved to source file
since MACRO's can collide with users MACRO when defined in header.

A example code is provided for custom serialization.

Related test codes are modified for custom serialization.

For threads safety, instance of SerializationConstants is created in
global space.

ClassCastException for portable identified and custom serializable
is added.

These fixes are backported from hazelcast#37

Remove singleton usage of SerializationConstants to avoid thread safety
issues.
  • Loading branch information
sancar committed Feb 8, 2016
1 parent 95c56d1 commit b49dc42
Show file tree
Hide file tree
Showing 18 changed files with 258 additions and 173 deletions.
1 change: 1 addition & 0 deletions examples/serialization/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
#
add_subdirectory(identified-data-serializable)
add_subdirectory(portable)
add_subdirectory(custom)
17 changes: 17 additions & 0 deletions examples/serialization/custom/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#
# Copyright (c) 2008-2015, Hazelcast, Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
add_executable(custom ./main.cpp)

91 changes: 91 additions & 0 deletions examples/serialization/custom/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2008-2015, Hazelcast, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <hazelcast/client/HazelcastClient.h>
#include <hazelcast/client/serialization/IdentifiedDataSerializable.h>
#include <hazelcast/client/serialization/ObjectDataInput.h>
#include <hazelcast/client/serialization/ObjectDataOutput.h>

class Person {
public:
Person() {
}

Person(const std::string& n) : name(n) {
}

void setName(const std::string& n) {
name = n;
}


const std::string& getName() const {
return name;
}

int getTypeId() const{
return 666;
}

private:
std::string name;
};



class CustomSerializer : public hazelcast::client::serialization::Serializer<Person> {
public:

void write(hazelcast::client::serialization::ObjectDataOutput & out, const Person& object) {
out.writeInt(666);
out.writeUTF(&(object.getName()));
out.writeInt(666);
}

void read(hazelcast::client::serialization::ObjectDataInput & in, Person& object) {
int i = in.readInt();
assert(i == 666);
object.setName(*(in.readUTF()));
i = in.readInt();
assert(i == 666);
}

int getTypeId() const {
return 666;
};
};

std::ostream &operator<<(std::ostream &out, const Person &p) {
const std::string & str = p.getName();
out << str;
return out;
}

int main() {
hazelcast::client::ClientConfig config;
hazelcast::client::SerializationConfig serializationConfig;
serializationConfig.registerSerializer(boost::shared_ptr<hazelcast::client::serialization::SerializerBase>(new CustomSerializer()));
config.setSerializationConfig(serializationConfig);
hazelcast::client::HazelcastClient hz(config);

hazelcast::client::IMap<std::string, Person> map = hz.getMap<std::string, Person>("map");
Person testPerson("bar");
map.put("foo", testPerson);
std::cout << *(map.get("foo")) << std::endl;
std::cout << "Finished" << std::endl;

return 0;
}

Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ namespace hazelcast {

/**
* Not public api. Do not override this method.
* @return serializer id
* @return type id
*/
virtual int getSerializerId() const;
virtual int getTypeId() const;

};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,15 @@ namespace hazelcast {
template<typename T>
boost::shared_ptr<T> readObject() {
int typeId = readInt();
if (pimpl::SerializationConstants::getInstance()->CONSTANT_TYPE_NULL == typeId) {
const pimpl::SerializationConstants& constants = portableContext.getConstants();
if (constants.CONSTANT_TYPE_NULL == typeId) {
return boost::shared_ptr<T>(static_cast<T *>(NULL));
} else {
std::auto_ptr<T> result(new T);
if (pimpl::SerializationConstants::getInstance()->CONSTANT_TYPE_DATA == typeId) {
constants.checkClassType(result->getTypeId() , typeId);
if (constants.CONSTANT_TYPE_DATA == typeId) {
readDataSerializable(reinterpret_cast<IdentifiedDataSerializable *>(result.get()));
} else if (pimpl::SerializationConstants::getInstance()->CONSTANT_TYPE_PORTABLE == typeId) {
} else if (constants.CONSTANT_TYPE_PORTABLE == typeId) {
readPortable(reinterpret_cast<Portable *>(result.get()));
} else {
readInternal<T>(typeId, result.get());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,9 @@ namespace hazelcast {
if (isEmpty) return;

if (NULL == object) {
writeInt(pimpl::SerializationConstants::getInstance()->CONSTANT_TYPE_NULL);
writeInt(pimpl::SerializationConstants::CONSTANT_TYPE_NULL);
} else {
writeInt(pimpl::SerializationConstants::getInstance()->CONSTANT_TYPE_PORTABLE);
writeInt(pimpl::SerializationConstants::CONSTANT_TYPE_PORTABLE);

writeInt(object->getFactoryId());
writeInt(object->getClassId());
Expand All @@ -189,9 +189,9 @@ namespace hazelcast {
if (isEmpty) return;

if (NULL == object) {
writeInt(pimpl::SerializationConstants::getInstance()->CONSTANT_TYPE_NULL);
writeInt(pimpl::SerializationConstants::CONSTANT_TYPE_NULL);
} else {
writeInt(pimpl::SerializationConstants::getInstance()->CONSTANT_TYPE_DATA);
writeInt(pimpl::SerializationConstants::CONSTANT_TYPE_DATA);
context->getSerializerHolder().getDataSerializer().write(*this, *object);
}
}
Expand All @@ -206,7 +206,7 @@ namespace hazelcast {
if (isEmpty) return;

if (NULL == serializable) {
writeInt(pimpl::SerializationConstants::getInstance()->CONSTANT_TYPE_NULL);
writeInt(pimpl::SerializationConstants::CONSTANT_TYPE_NULL);
} else {
const T *object = static_cast<const T *>(serializable);
int type = object->getTypeId();
Expand Down
4 changes: 2 additions & 2 deletions hazelcast/include/hazelcast/client/serialization/Portable.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ namespace hazelcast {

/**
* Not public api. Do not override this method.
* @return serializer id
* @return type id
*/
virtual int getSerializerId() const;
virtual int getTypeId() const;
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ namespace hazelcast {
* User than can register serializer via SerializationConfig as follows
*
clientConfig.getSerializationConfig().registerSerializer(new MyCustomSerializer());
clientConfig.getSerializationConfig().registerSerializer(
boost::shared_ptr<hazelcast::client::serialization::SerializerBase>(new MyCustomSerializer());
*/
template <typename Serializable>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,12 @@ namespace hazelcast {

class ClassDefinitionContext;

class SerializationConstants;

class HAZELCAST_API PortableContext {
public:

PortableContext(int);
PortableContext(int version,const SerializationConstants& constants);

int getClassVersion(int factoryId, int classId);

Expand All @@ -69,6 +71,9 @@ namespace hazelcast {

SerializerHolder &getSerializerHolder();


SerializationConstants const& getConstants() const;

private:

PortableContext(const PortableContext &);
Expand All @@ -80,7 +85,7 @@ namespace hazelcast {
int contextVersion;
util::SynchronizedMap<int, ClassDefinitionContext> classDefContextMap;
SerializerHolder serializerHolder;

const SerializationConstants& constants;
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,41 +39,40 @@ namespace hazelcast {
namespace pimpl {
class HAZELCAST_API SerializationConstants {
public:
int const CONSTANT_TYPE_NULL;
int const CONSTANT_TYPE_PORTABLE;
int const CONSTANT_TYPE_DATA;
int const CONSTANT_TYPE_BYTE;
int const CONSTANT_TYPE_BOOLEAN;
int const CONSTANT_TYPE_CHAR;
int const CONSTANT_TYPE_SHORT;
int const CONSTANT_TYPE_INTEGER;
int const CONSTANT_TYPE_LONG;
int const CONSTANT_TYPE_FLOAT;
int const CONSTANT_TYPE_DOUBLE;
int const CONSTANT_TYPE_STRING;
int const CONSTANT_TYPE_BYTE_ARRAY;
int const CONSTANT_TYPE_BOOLEAN_ARRAY;
int const CONSTANT_TYPE_CHAR_ARRAY;
int const CONSTANT_TYPE_SHORT_ARRAY;
int const CONSTANT_TYPE_INTEGER_ARRAY;
int const CONSTANT_TYPE_LONG_ARRAY;
int const CONSTANT_TYPE_FLOAT_ARRAY;
int const CONSTANT_TYPE_DOUBLE_ARRAY;
int const CONSTANT_TYPE_STRING_ARRAY;
SerializationConstants();

static int const CONSTANT_TYPE_NULL;
static int const CONSTANT_TYPE_PORTABLE;
static int const CONSTANT_TYPE_DATA;
static int const CONSTANT_TYPE_BYTE;
static int const CONSTANT_TYPE_BOOLEAN;
static int const CONSTANT_TYPE_CHAR;
static int const CONSTANT_TYPE_SHORT;
static int const CONSTANT_TYPE_INTEGER;
static int const CONSTANT_TYPE_LONG;
static int const CONSTANT_TYPE_FLOAT;
static int const CONSTANT_TYPE_DOUBLE;
static int const CONSTANT_TYPE_STRING;
static int const CONSTANT_TYPE_BYTE_ARRAY;
static int const CONSTANT_TYPE_BOOLEAN_ARRAY;
static int const CONSTANT_TYPE_CHAR_ARRAY;
static int const CONSTANT_TYPE_SHORT_ARRAY;
static int const CONSTANT_TYPE_INTEGER_ARRAY;
static int const CONSTANT_TYPE_LONG_ARRAY;
static int const CONSTANT_TYPE_FLOAT_ARRAY;
static int const CONSTANT_TYPE_DOUBLE_ARRAY;
static int const CONSTANT_TYPE_STRING_ARRAY;

// ------------------------------------------------------------

std::string typeIdToName(int typeId);
void checkClassType(int expectedType, int currentType) const;

static SerializationConstants *getInstance();
private:
const int size;
std::vector<std::string> typeIdNameVector;

static SerializationConstants *instance;

SerializationConstants();

int idToIndex(int id);
int idToIndex(int id) const;
std::string typeIdToName(int typeId) const;
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,6 @@ namespace hazelcast {
namespace pimpl {
class HAZELCAST_API SerializationService {
public:
#define CHECK_NULL(type) \
if (isNullData(data)) { \
return boost::shared_ptr<type >(); \
}\

SerializationService(const SerializationConfig& serializationConfig);

Expand All @@ -77,7 +73,7 @@ namespace hazelcast {

writeHash(output);

writeObject<T>(dataOutput, object);
dataOutput.writeObject<T>(object);

Data data(output.toByteArray());
return data;
Expand All @@ -93,46 +89,32 @@ namespace hazelcast {

template<typename T>
inline boost::shared_ptr<T> toObject(const Data &data) {
CHECK_NULL(T);
if (isNullData(data)) {
return boost::shared_ptr<T>();
}

// Constant 4 is Data::TYPE_OFFSET. Windows DLL export does not
// let usage of static member.
DataInput dataInput(data.toByteArray(), 4);

return readObject<T>(dataInput);
ObjectDataInput objectDataInput(dataInput, portableContext);
return objectDataInput.readObject<T>();
}

PortableContext &getPortableContext();

const byte getVersion() const;

private:
template <typename T>
inline boost::shared_ptr<T> readObject(DataInput &data) {
ObjectDataInput dataInput(data, portableContext);
return dataInput.readObject<T>();
}

template <typename T>
inline void writeObject(ObjectDataOutput &dataOutput, const T *object) {
dataOutput.writeObject<T>(object);
}

SerializerHolder &getSerializerHolder();

boost::shared_ptr<SerializerBase> serializerFor(int typeId);

SerializationService(const SerializationService &);

SerializationService &operator = (const SerializationService &);

SerializationConstants constants;
PortableContext portableContext;

const SerializationConfig& serializationConfig;

void checkClassType(int expectedType, int currentType);

static bool isNullData(const Data &data);
bool isNullData(const Data &data);

void writeHash(DataOutput &out);
};
Expand Down
12 changes: 0 additions & 12 deletions hazelcast/include/hazelcast/util/IOUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,6 @@ namespace hazelcast {

static void closeResource(Closeable *closable);

enum PRIMITIVE_ID {
PRIMITIVE_TYPE_BOOLEAN = 1,
PRIMITIVE_TYPE_BYTE = 2,
PRIMITIVE_TYPE_SHORT = 3,
PRIMITIVE_TYPE_INTEGER = 4,
PRIMITIVE_TYPE_LONG = 5,
PRIMITIVE_TYPE_FLOAT = 6,
PRIMITIVE_TYPE_DOUBLE = 7,
PRIMITIVE_TYPE_UTF = 8,
PRIMITIVE_TYPE_NULL = 9
};

};
}
}
Expand Down
Loading

0 comments on commit b49dc42

Please sign in to comment.