Hazelcast is ideally used in an environment where data/query are distributed across machines. This requires data to be serialized from our Java objects to a byte array which can be transferred over the network.
Hazelcast supports various types of Serialization. However, let’s look at some commonly used ones, i.e., Java Serialization and Java Externalizable.
Java Serialization
Example
First, let’s look at Java Serialization. Let’s say, we define an Employee class with a Serializable interface implemented.
public class Employee implements Serializable{
private static final long serialVersionUID = 1L;
private String name;
private String department;
public Employee(String name, String department) {
super();
this.name = name;
this.department = department;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
@Override
public String toString() {
return "Employee [name=" + name + ", department=" + department + "]";
}
}
Let’s now write code to add the Employee object to the Hazelcast map.
public class EmployeeExample {
public static void main(String... args){
//initialize hazelcast server/instance
HazelcastInstance hazelcast = Hazelcast.newHazelcastInstance();
//create a set to track employees
Map<Employee, String> employeeOwners=hazelcast.getMap("employeeVehicleMap");
Employee emp1 = new Employee("John Smith", "Computer Science");
// add employee to set
System.out.println("Serializing key-value and add to map");
employeeOwners.put(emp1, "Honda");
// check if emp1 is present in the set
System.out.println("Serializing key for searching and Deserializing
value got out of map");
System.out.println(employeeOwners.get(emp1));
// perform a graceful shutdown
hazelcast.shutdown();
}
}
Output
It will produce the following output −
Serializing key-value and add to map
Serializing key for searching and Deserializing value got out of map
Honda
A very important aspect here is that simply by implementing a Serializable interface, we can make Hazelcast use Java Serialization. Also, note that Hazelcast stores serialized data for key and value instead of storing it in memory like HashMap. So, Hazelcast does the heavy-lifting of Serialization and Deserialization.
Example
However, there is a pitfall here. In the above case, what if the department of the employee changes? The person is still the same.
public class EmployeeExampleFailing {
public static void main(String... args){
//initialize hazelcast server/instance
HazelcastInstance hazelcast = Hazelcast.newHazelcastInstance();
//create a set to track employees
Map<Employee, String> employeeOwners=hazelcast.getMap("employeeVehicleMap");
Employee emp1 = new Employee("John Smith", "Computer Science");
// add employee to map
System.out.println("Serializing key-value and add to map");
employeeOwners.put(emp1, "Honda");
Employee empDeptChange = new Employee("John Smith", "Electronics");
// check if emp1 is present in the set
System.out.println("Checking if employee with John Smith is present");
System.out.println(employeeOwners.containsKey(empDeptChange));
Employee empSameDept = new Employee("John Smith", "Computer Science");
System.out.println("Checking if employee with John Smith is present");
System.out.println(employeeOwners.containsKey(empSameDept));
// perform a graceful shutdown
hazelcast.shutdown();
}
}
Output
It will produce the following output −
Serializing key-value and add to map
Checking if employee with name John Smith is present
false
Checking if employee with name John Smith is present
true
It is because Hazelcast does not deserialize the key, i.e., Employee while comparison. It directly compares the bytecode of the serialized key. So, an object with the same value to all the attributes would be treated the same. But if the value to those attributes changes, for example, department in the above scenario, those two keys are treated as unique.
Java Externalizable
What if, in the above example, we don’t care about the value of the department while performing serialization/deserialization of keys. Hazelcast also supports Java Externalizable which gives us control over what tags are used for serialization and deserialization.
Example
Let’s modify our Employee class accordingly −
public class EmplyoeeExternalizable implements Externalizable {
private static final long serialVersionUID = 1L;
private String name;
private String department;
public EmplyoeeExternalizable(String name, String department) {
super();
this.name = name;
this.department = department;
}
@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
System.out.println("Deserializaing....");
this.name = in.readUTF();
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
System.out.println("Serializing....");
out.writeUTF(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
@Override
public String toString() {
return "Employee [name=" + name + ", department=" + department + "]";
}
}
So, as you can see from the code, we have added readExternal/writeExternal methods which are responsible for serialization/deserialization. Given that we are not interested in the department while serialization/deserialization, we exclude those in readExternal/writeExternal methods.
Example
Now, if we execute the following code −
public class EmployeeExamplePassing {
public static void main(String... args){
//initialize hazelcast server/instance
HazelcastInstance hazelcast = Hazelcast.newHazelcastInstance();
//create a set to track employees
Map<EmplyoeeExternalizable, String> employeeOwners=hazelcast.getMap("employeeVehicleMap");
EmplyoeeExternalizable emp1 = new EmplyoeeExternalizable("John Smith", "Computer Science");
// add employee to map
employeeOwners.put(emp1, "Honda");
EmplyoeeExternalizable empDeptChange = new EmplyoeeExternalizable("John Smith", "Electronics");
// check if emp1 is present in the set
System.out.println("Checking if employee with John Smith is present");
System.out.println(employeeOwners.containsKey(empDeptChange));
EmplyoeeExternalizable empSameDept = new EmplyoeeExternalizable("John Smith", "Computer Science");
System.out.println("Checking if employee with John Smith is present");
System.out.println(employeeOwners.containsKey(empSameDept));
// perform a graceful shutdown
hazelcast.shutdown();
}
}
Output
The output we get is −
Serializing....
Checking if employee with John Smith is present
Serializing....
true
Checking if employee with John Smith is present
Serializing....
true
As the output shows, using an Externalizable interface, we can provide Hazelcast with serialized data for only the name of the employee.
Also, note that Hazelcast serializes our key twice −
- Once while storing the key,
- And, second for searching the given key in the map. As stated earlier, this is because Hazelcast uses serialized byte arrays for key comparison.
Overall, using Externalizable has more benefits as compared to Serializable if we want to have more control over what attributes are to be serialized and how we want to handle them.