Kryo is a graph serialization framework written in Java to address both speed and efficiency with an easy to use API. This framework helps in copying direct from one Java object to another and it simplifies the process of sending Java objects over a network or to store them in a file or database.
Now, let’s understand in brief the process summary of Kryo framework as mentioned below:
- The main entry point is Kryo class.
- It manages the serialization process and maps classes to Serializer instances. Further handles the details of converting an object’s graph to a byte representation.
- Once the bytes are ready, an output object is used to write them to a stream using an output object. This way they can be stored in a file, a database or transmitted over the network.
- When the object is needed, an input instance is used to read those bytes and decode them into Java objects.
In this blog, I will try to analyze the important features of the Kryo framework and share examples to demonstrate its potential.
Prerequisites
Java
- 1.7 version or higher
Maven
- 3.5.* or higher
Kryo
- 5.3.0
IDE
- Intellij IDEA
Let’s now start by creating a maven project in IntelliJ and include the below mentioned dependencies in pom.xml.
Maven dependencies:
<p><script src="https://gist.github.com/sudarshan-suresh/318073614ce38c09b3c7b40bb2916a81.js?file=sample.pom"></script></p>
The created project structure should look like below.
package com.example
Test Class: KryoTest (Junit)
gist: <script src="https://gist.github.com/sudarshan-suresh/318073614ce38c09b3c7b40bb2916a81.js?file=KryoTest.java"></script>
Please note that if you are writing objects in a file, then those objects will be read in the same order. For instance, if you are writing a string and a date class, then the string will appear first and then the date.
It is to write and read an object using Kryo. We can analyze the process by adding setup method to the Test class.
gist: <script src="https://gist.github.com/sudarshan-suresh/318073614ce38c09b3c7b40bb2916a81.js?file=Setup.java"></script>
@Before will make sure the setup is done before running each test case. The output and input variable represents com.esotericsoftware.kryo.io.Output and
com.esotericsoftware.kryo.io.Input respectively.
gist: <script src="https://gist.github.com/sudarshan-suresh/318073614ce38c09b3c7b40bb2916a81.js?file=Test1.java"></script>
In the above test we used a method called writeClassAndObject to write to the output stream and readClassAndObject to read from the input stream.
We need to close output and input classes as they are inherited from OutputStream and InputStream respectively.
Serializing multiple objects is similarly easy:
gist: <script src="https://gist.github.com/sudarshan-suresh/318073614ce38c09b3c7b40bb2916a81.js?file=MultiObjectTest.java"></script>
If you look at the code, you will find that it is cast-free now when I am passing the relevant java class to the readObject() method. Also, you need to register appropriate classes to Kryo, in this case I registered employee and date class (because I am using a date field in employee class).
Serializers
In this section, I will cover default serializers that are already available, and then create one.
Default Serializers
While registering a class, a serializer instance can be optionally specified. During deserialization, the registered class must have the exact same serializers and serializer configurations they had during serialization.
If a custom serializer is not specified or when an unregistered class is encountered, a serializer is chosen automatically from a list of “default serializers”. It then maps a class to a serializer. The FieldSerializer acts as a global default serializer in such scenarios and it pretty much can handle almost any type of object.
50+ default serializers are available in Kryo and additional default serializers can be added without compromising its performance.
Let’s see how this looks like. First, let’s create an Employee class.
gist: <script src="https://gist.github.com/sudarshan-suresh/318073614ce38c09b3c7b40bb2916a81.js?file=Employee.java"></script>
Now, we will write an object from this class to a file and then read it back.
gist: <script src="https://gist.github.com/sudarshan-suresh/318073614ce38c09b3c7b40bb2916a81.js?file=TestEmployee.java"></script>
It’s evident from the steps that we have to register our employee class as well as date class for successful serialization.
Custom Serializers
At times, you might require more control over the serialization process. If you encounter a similar scenario, you only have two options- either write your own custom serializer class and register it with Kryo or let the class handle the serialization by itself by implementing KryoSerializable interface.
To demonstrate the first option, let’s create a class that extends Serializer.
gist: <script src="https://gist.github.com/sudarshan-suresh/318073614ce38c09b3c7b40bb2916a81.js?file=EmployeeSerializer.java"></script>
Now, let’s put it to the test.
gist: <script src="https://gist.github.com/sudarshan-suresh/318073614ce38c09b3c7b40bb2916a81.js?file=TestCustomEmployee.java"></script>
For the second option, let’s modify our Employee class to extend the KryoSerializable interface.
gist: <script src="https://gist.github.com/sudarshan-suresh/318073614ce38c09b3c7b40bb2916a81.js?file=Sample2.java"></script>
Java Serializer
There are some random scenarios, where custom serializer or FieldSerializer won’t be able to serialize a custom class. In such cases, it is better to use the standard Java serialization mechanism using a JavaSerializer.
Here’s an example that uses the above serializer.
gist: <script src="https://gist.github.com/sudarshan-suresh/318073614ce38c09b3c7b40bb2916a81.js?file=Student.java"></script>
gist: <script src="https://gist.github.com/sudarshan-suresh/318073614ce38c09b3c7b40bb2916a81.js?file=TestStudent.java"></script>
Conclusion
In this blog, we have explored the prime features of the Kryo framework and ways to serialize simple and multiple Java objects. In fact, I have also described how to serialize the custom Java class using FieldSerializer class and the process to create a custom serializer instead of FieldSerializer. Finally, I demonstrated how to fall back to the standard Java serialization mechanism if needed. So, you can now go ahead and try out the methods given above. You can also download the entire code base from github.