Kryo

serializationJavabinary-serializationhigh-performanceefficientobject-graph

Serialization Library

Kryo

Overview

Kryo is a fast and efficient binary object graph serialization framework for Java. The goals of the project are high speed, low size, and an easy to use API. The project is useful any time objects need to be persisted, whether to a file, database, or over the network.

Details

Kryo provides significantly better performance compared to standard Java serialization and produces smaller serialized data. It supports automatic deep and shallow object copying and properly handles multiple references and circular references.

Key Features

  • High Performance: Significantly faster than standard Java serialization
  • Compact Output: Smaller serialized data size
  • Automatic Serialization: Provides default serializers for primitives, lists, maps, enums, etc.
  • Custom Serializers: Define custom serialization processes for specific classes
  • Complex Object Graph Support: Properly handles circular references and nested objects
  • Not Thread-Safe: Designed for high performance, not thread-safe by design
  • Pluggable Architecture: Flexible integration of different serializers

Common Use Cases

  • Big Data Processing: Data serialization between distributed nodes in frameworks like Apache Spark
  • Network Communication: Applications requiring fast data transmission
  • Caching: Fast object serialization in caching solutions
  • Persistent Storage: Applications storing large amounts of data efficiently

Pros and Cons

Pros

  • High Speed: 50%+ faster than standard Java serialization
  • Small Payload Size: 61% size reduction without compression, 80% with compression
  • Flexible Serialization: Can serialize classes not implementing java.io.Serializable
  • Mature Implementation: Used in production by Twitter, Groupon, Yahoo, Hive, Storm, and more
  • Simple API: Intuitive and easy-to-use API design
  • Object Copy Feature: Easy implementation of deep and shallow copy

Cons

  • Lack of Version Compatibility: Serialization compatibility not guaranteed between releases
  • Not Suitable for Long-term Storage: Not recommended for long-term data storage
  • Not Thread-Safe: Requires proper synchronization or pooling in multi-threaded environments
  • Registration Required: Pre-registration of classes needed for best performance
  • No-arg Constructor Required: No-arg constructor needed for optimal performance

Reference Pages

Code Examples

Basic Usage

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import java.io.*;

public class KryoExample {
    public static void main(String[] args) throws Exception {
        Kryo kryo = new Kryo();
        
        // Register classes for better performance
        kryo.register(Person.class);
        
        Person person = new Person("John Doe", 30);
        
        // Serialize to file
        Output output = new Output(new FileOutputStream("person.bin"));
        kryo.writeObject(output, person);
        output.close();
        
        // Deserialize from file
        Input input = new Input(new FileInputStream("person.bin"));
        Person restoredPerson = kryo.readObject(input, Person.class);
        input.close();
        
        System.out.println(restoredPerson);
    }
    
    static class Person {
        String name;
        int age;
        
        // Kryo requires no-arg constructor
        public Person() {}
        
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
        
        @Override
        public String toString() {
            return "Person{name='" + name + "', age=" + age + "}";
        }
    }
}

Serialization with Unknown Class

// Write with class information
kryo.writeClassAndObject(output, someObject);

// Read with class information
Object object = kryo.readClassAndObject(input);

// Handle nullable objects
kryo.writeObjectOrNull(output, maybeNullObject);
SomeClass object = kryo.readObjectOrNull(input, SomeClass.class);

Custom Serializer Implementation

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import java.time.LocalDateTime;

public class LocalDateTimeSerializer extends Serializer<LocalDateTime> {
    @Override
    public void write(Kryo kryo, Output output, LocalDateTime dateTime) {
        output.writeLong(dateTime.toEpochSecond(java.time.ZoneOffset.UTC));
        output.writeInt(dateTime.getNano());
    }
    
    @Override
    public LocalDateTime read(Kryo kryo, Input input, Class<LocalDateTime> type) {
        long epochSecond = input.readLong();
        int nano = input.readInt();
        return LocalDateTime.ofEpochSecond(epochSecond, nano, java.time.ZoneOffset.UTC);
    }
}

// Usage
Kryo kryo = new Kryo();
kryo.register(LocalDateTime.class, new LocalDateTimeSerializer());

Thread-Safe Usage (Pooling)

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.util.Pool;

public class KryoPool {
    private static final Pool<Kryo> kryoPool = new Pool<Kryo>(true, false, 8) {
        protected Kryo create() {
            Kryo kryo = new Kryo();
            // Register required classes
            kryo.register(Person.class);
            kryo.register(Address.class);
            // Other configurations
            return kryo;
        }
    };
    
    public static byte[] serialize(Object object) {
        Kryo kryo = kryoPool.obtain();
        try (Output output = new Output(1024, -1)) {
            kryo.writeClassAndObject(output, object);
            return output.toBytes();
        } finally {
            kryoPool.free(kryo);
        }
    }
    
    public static Object deserialize(byte[] bytes) {
        Kryo kryo = kryoPool.obtain();
        try (Input input = new Input(bytes)) {
            return kryo.readClassAndObject(input);
        } finally {
            kryoPool.free(kryo);
        }
    }
}

Reference Handling

Kryo kryo = new Kryo();

// Enable references (default) - handles circular references but slower
kryo.setReferences(true);

// Disable references - faster but stack overflow with circular references
kryo.setReferences(false);

// Disable references for specific serializer only
kryo.register(SomeClass.class, new FieldSerializer(kryo, SomeClass.class) {{
    setReferences(false);
}});

Object Copying

Kryo kryo = new Kryo();

// Deep copy
Person originalPerson = new Person("Jane Smith", 25);
Person deepCopy = kryo.copy(originalPerson);

// Shallow copy
Person shallowCopy = kryo.copyShallow(originalPerson);

// Copy configuration
kryo.setCopyReferences(true);  // Preserve references
kryo.setCopyTransient(false);  // Don't copy transient fields

Maven Dependency

<dependency>
    <groupId>com.esotericsoftware</groupId>
    <artifactId>kryo</artifactId>
    <version>5.6.2</version>
</dependency>

Gradle Dependency

implementation 'com.esotericsoftware:kryo:5.6.2'