Serialization
For data to be sent over a network between cluster members and/or clients, it needs to be serialized into raw bytes. Hazelcast has many serialization options to choose from, depending on what you plan on doing with your data.
You can store any primitive types in a Hazelcast data structure and Hazelcast will serialize them for you, using built-in serializers. But, to store custom classes or objects, you need to tell a cluster how to serialize and deserialize them when they are sent over the network.
Hazelcast supports the following serialization options:
IdentifiedDataSerializable serialization is supported by all clients. It is an Hazelcast-specific method that require that a specific interface be implemented.
Portable serialization is supported by all clients. It is an Hazelcast-specific method that require that a specific interface be implemented. Versionning and partial deserialization are supported. Class definitions are also sent with data, but store only once per class.
Custom serialization is supported by all clients. It does not require classes to implement a specific interface and is the most flexible method. However, it requires more work to implement.
Compact serialization (introduced in version 5.2) is a schema-based Hazelcast-specific method that can handle plain POCOs (no need to implement a specific interface), supports schema evolution and partial deserialization. It is supported by all clients. Class definitions (schemas) are not part of the data but distribued between clients and clusters.
HazelcastJsonValue serialization is supported by all clients. It is an Hazelcas-specific method that requires no member-side coding, but requires extra metadata to be stored on members.
Serialization Priority
When Hazelcast .NET client serializes an object:
- If the object is
null
, use the internalnull
serializer, else - If a compact serializer has been register for the type of the object, use Compact serialization, else
- If the object implements the
Hazelcast.Serialization.IIdentifiedDataSerializable
interface, use IdentifiedDataSerializable, else - If the object implements the
Hazelcast.Serialization.IPortable
interface, use Portable serialization. - If the object type is one of the default built-in types (see below), use the corresponding serializer, else
- Look for a Custom serializer, i.e., an implementation of
IByteArraySerializer<T>
orIStreamSerializer<T>
. Custom serializer is searched using the input object’s class and its parent class up toObject
. If parent class search fails, all interfaces implemented by the class are also checked (note that the order in which these interfaces are checked is not specified). - If the object is Serializable (
Type.IsSerializable
) and a Global Serializer is not registered with CLR serialization Override feature, serialize via .NETBinaryFormatter
(see note below) - If a Global serializer (see below) has been registered, use it, else
- Use Compact serialization reflection-based mode.
Note that, at the moment, there is no built-in automatic support for IEnumerable<T>
or T[]
beyond the default types documented above.
.NET Binary Formatter Serialization
For backward-compatibility reasons, .NET BinaryFormatter
serialization is enabled by default. However, it is now considered obsolete by Microsoft that issued the following warning:
Warning
The BinaryFormatter
type is dangerous and is not recommended for data processing. Applications should stop using BinaryFormatter
as soon as possible, even if they believe the data they're processing to be trustworthy. BinaryFormatter
is insecure and can't be made secure. (source)
Warning
Starting from Hazelcast .Net Client 5.4.0 on .Net 8.0 build, BinaryFormatter
serialization is removed. CLR serialization is not available anymore on the client.
Default Types
Hazelcast serializes all your objects before sending them to the server. The built-in primitive types are serialized natively and you cannot override this behavior. The following table is the conversion of types for Java server side.
.NET | Java |
---|---|
bool | Boolean |
byte | Byte |
char | Character |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
string | String |
and
.NET | Java |
---|---|
DateTime | java.util.Date |
System.Numeric.BigInteger | java.math.BigInteger |
Guid | java.util.UUID |
Arrays of the above types can be serialized as bool[]
, byte[]
, short[]
, int[]
, long[]
, float[]
, double[]
, char[]
and string[]
.
Global Serialization
The global serializer is identical to custom serializers from the implementation perspective. It is registered as a fallback serializer to handle all other objects if a serializer cannot be located for them. By default, the global serializer does not handle .NET Serializable instances. However, you can configure it to be responsible for those instances.
When the Global Serialization OverrideClrSerialization
is set to true
(it is false
by default), .NET Serialization serialization is de-activated.
A custom serializer should be registered for a specific class type. The global serializer will handle all class types if all the steps in searching for a serializer, as described previously, fail.
Use cases
- Third party serialization frameworks can be integrated using the global serializer.
- For your custom objects, you can implement a single serializer to handle all of them.
A sample global serializer that integrates with a third party serializer is shown below.
public class GlobalSerializer : IStreamSerializer<object>
{
public const int TypeId = 20;
public void Write(IObjectDataOutput output, object obj)
{
output.write(MyFavoriteSerializer.Serialize(obj))
}
public object Read(IObjectDataInput input)
{
return MyFavoriteSerializer.Deserialize(input);
}
int ISerializer.TypeId => TypeId;
}
You should register the global serializer in the configuration.
Programmatic Configuration:
var hazelcastOptions = new HazelcastOptionsBuilder().Build();
hazelcastOptions.Serialization.GlobalSerializer.Creator =
() => new GlobalSerializer();
Declarative Configuration:
{
"hazelcast": {
"serialization": {
"globalSerializer": {
"serializedTypeName": "CustomSerializableType",
"overrideClrSerialization": true
}
}
}
}