-
Notifications
You must be signed in to change notification settings - Fork 1
KryoSerializer Generator
Working with Kryo can be error prone when you have many domain classes. For data grid products, for example, you are left with the task of manually and individually registering each class by assigning a unique ID. Even with a few domain classes, this can quickly become a time consuming and error pone task.
To alleviate this problem, PadoGrid includes the t_generate_kryo_serializer
command that generates a KryoSerializer
class for the specified Java package where your domain classes are located. It automatically and optimally registers all the classes found in the specified package. This is done by assigning the specified type ID to the serializer and reserving a single byte to uniquely identify the domain classes found in the specified package. The class ID begins from 0x00 and reserves 0xFF for undefined classes allowing up to 255 classes per package. If you have more than 255 domain classes in a package, then you must split them into smaller packages with not more than 255 classes.
If KryoSerialzer
already exists in the package and new classes are added in the package since KryoSerialzer
is last created, then t_generate_kryo_serializer
appends the new classes to the existing KryoSerializer
class by incrementing the last class ID. This ensures the preservance of the existing class IDs.
The following example generates KryoSerializer
in the src/main/java
directory for the example.domain
package that contains domain classes found in the lib/example-domain.jar
file. It also picks up dependencies from the lib
directory and assigns the unique ID 1200 to the generated class.
t_generate_kryo_serializer -id 1200 \
-package example.domain \
-dir src/main/java \
-jar lib/example-domain.jar \
-classpath lib
The generated class for each data grid product is shown below.
package example.domain;
import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.geode.DataSerializer;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
/**
* This class is generated by the PadoGrid Code Generator. You may modify this
* class as needed. It will not be overwritten when you generate it again later.
*
* @since Mon Apr 25 08:51:05 EDT 2022
* @author dpark
* @see <a href="https://github.com/padogrid/padogrid">https://github.com/padogrid/padogrid</a>
*/
public class KryoSerializer extends DataSerializer {
private static final ThreadLocal<Kryo> kryoThreadLocal = new ThreadLocal<Kryo>() {
@Override
protected Kryo initialValue() {
Kryo kryo = new Kryo();
return kryo;
}
};
private static Class<?>[] classes = new Class<?>[] {
Customer.class, Order.class, Category.class, Employee.class
};
private static Map<Class<?>, Integer> classMap = new HashMap<Class<?>, Integer>(classes.length, 1f);
static {
int i = 0;
for (Class<?> clazz : classes) {
classMap.put(clazz, i++);
}
}
public static List<Class<?>> getClassList()
{
return Collections.unmodifiableList(Arrays.asList(classes));
}
public static Integer getClassId(Class<?> clazz) {
return classMap.get(clazz);
}
public static int getLastClassId()
{
return classes.length - 1;
}
@Override
public Class<?>[] getSupportedClasses() {
return classes;
}
@Override
public int getId() {
return 1200;
}
private int getWriteTypeId(Object obj)
{
if (obj == null) {
return 0xFF;
}
Class<?> clazz = obj.getClass();
return classMap.get(clazz);
}
private Object readKryo(Input input, Kryo kryo, int typeId)
{
if (typeId < 0 || typeId >= classes.length) {
return null;
}
kryo.register(classes[typeId]);
return kryo.readObject(input, classes[typeId]);
}
@Override
public boolean toData(Object obj, DataOutput out) throws IOException {
Kryo kryo = kryoThreadLocal.get();
out.writeByte(getWriteTypeId(obj));
kryo.register(obj.getClass());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Output output = new Output(baos);
kryo.writeObject(output, obj);
output.flush();
out.writeInt(baos.size());
out.write(baos.toByteArray());
return true;
}
@Override
public Object fromData(DataInput in) throws IOException, ClassNotFoundException {
byte typeId = in.readByte();
int size = in.readInt();
byte[] buffer = new byte[size];
in.readFully(buffer);
Input input = new Input(buffer);
Kryo kryo = kryoThreadLocal.get();
return readKryo(input, kryo, typeId);
}
}
package example.domain;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.hazelcast.nio.ObjectDataInput;
import com.hazelcast.nio.ObjectDataOutput;
import com.hazelcast.nio.serialization.StreamSerializer;
/**
* This class is generated by the PadoGrid Code Generator. You may modify this
* class as needed. It will not be overwritten when you generate it again later.
*
* @since Mon Apr 25 12:16:32 EDT 2022
* @author dpark
* @see <a href="https://github.com/padogrid/padogrid">https://github.com/padogrid/padogrid</a>
*/
public class KryoSerializer implements StreamSerializer<Object> {
private static final ThreadLocal<Kryo> kryoThreadLocal = new ThreadLocal<Kryo>() {
@Override
protected Kryo initialValue() {
Kryo kryo = new Kryo();
return kryo;
}
};
private static Class<?>[] classes = new Class<?>[] {
Customer.class, Order.class, Category.class, Employee.class
};
private static Map<Class<?>, Integer> classMap = new HashMap<Class<?>, Integer>(classes.length, 1f);
static {
int i = 0;
for (Class<?> clazz : classes) {
classMap.put(clazz, i++);
}
}
public static List<Class<?>> getClassList()
{
return Collections.unmodifiableList(Arrays.asList(classes));
}
public static Integer getClassId(Class<?> clazz) {
return classMap.get(clazz);
}
public static int getLastClassId()
{
return classes.length - 1;
}
@Override
public int getTypeId() {
return 1200;
}
@Override
public void destroy() {
kryoThreadLocal.remove();
}
private int getWriteTypeId(Object obj)
{
if (obj == null) {
return 0xFF;
}
Class<?> clazz = obj.getClass();
return classMap.get(clazz);
}
private Object readKryo(Input input, Kryo kryo, int typeId)
{
if (typeId < 0 || typeId >= classes.length) {
return null;
}
kryo.register(classes[typeId]);
return kryo.readObject(input, classes[typeId]);
}
@Override
public void write(ObjectDataOutput odout, Object obj) throws IOException {
Kryo kryo = kryoThreadLocal.get();
odout.writeByte(getWriteTypeId(obj));
kryo.register(obj.getClass());
Output output = new Output((OutputStream) odout);
kryo.writeObject(output, obj);
output.flush();
}
@Override
public Object read(ObjectDataInput odin) throws IOException {
byte typeId = odin.readByte();
InputStream in = (InputStream) odin;
Input input = new Input(in);
Kryo kryo = kryoThreadLocal.get();
return readKryo(input, kryo, typeId);
}
}
Once the KryoSerializer
class is generated, instead of registering each domain class, i.e., Customer.class
, Order.class
, Category.class
, and Employee.class
, you would simply register the KryoSerializer
class in the data grid as follows.
<cache>
...
<serialization-registration>
<serializer>
<class-name>example.KryoSerializer</class-name>
</serializer>
</serialization-registration>
...
</cache>
<hazelcast>
...
<serialization>
<serializers>
<global-serializer override-java-serialization="true">
example.domain.KryoSerializer
</global-serializer>
</serializers>
</serialization>
...
</hazelcast>
The following bundles provide step-by-step instructions for generating Avro and Kryo classes using PadoGrid code generators.
- Geode/GemFire Kryo/Avro Code Generator, https://github.com/padogrid/bundle-geode-1-app-kryo_codegen.
- Hazelcast Kryo/Avro Code Generator, https://github.com/padogrid/bundle-hazelcast-4n5-app-kryo_codegen.
PadoGrid Manual
Overview
- Home
- PadoGrid in 5 Minutes
- Quick Start
- Introduction
- Bundle Catalogs
- Building PadoGrid
- Supported Data Grid Products and Downloads
- PadoGrid Components
- Installing PadoGrid
- Root Workspaces Environments (RWEs)
- Initializing PadoGrid
- Bash Auto-Completion
- Viewing PadoGrid Summaries
- Updating Products
- Upgrading PadoGrid
- Migrating Workspaces
- PadoGrid Pods
- Kubernetes
- Docker
- Apps
- Software List
Operations
- Workspace Lifecycle Management
- Creating RWE
- Creating Workspace and Starting Cluster
- Managing Workspaces
- Understanding Workspaces
- Understanding Clusters
- Running Clusters
- Default Port Numbers
- Running Clusters Independent of PadoGrid
- Running Apps
- Understanding Groups
- Running Groups
- Understanding Bundles
- User Bundle Repos
- Using Bundle Templates
- Bundle Repo Guidelines
- User Bundle Catalogs
- Private Bundle Repos
- Gitea Repos
- Running Bundles in Container
- PadoGrid Addon Jars
- Understanding PadoGrid Pods
- Tested Vagrant Boxes
- VM-Enabled Pods
- Multitenancy
- Multitenancy Best Practices
- PadoGrid Configuration Files
Tools
Platforms
Clouds
Pado
Geode/GemFire
- Geode CLASSPATH
- Geode Kubernetes
- Geode Minikube
- Geode Minikube on WSL
- Geode Docker Compose
- Geode Grafana App
- Geode
perf_test
App - Geode WAN Example
- Geode Workspaces on VMs
- Geode on AWS EC2
- Reactivating Geode Workspaces on AWS EC2
Hazelcast/Jet
- Hazelcast CLASSPATH
- Creating Jet Workspace
- Configuring Hazelcast Addon
- HQL Query
- Hazelcast Kubernetes
- Hazelcast GKE
- Hazelcast Minikube
- Hazelcast Minikube on WSL
- Hazelcast Minishift/CDK
- Hazelcast OpenShift
- Hazelcast Docker Compose
- Hazelcast Desktop App
- Hazelcast Grafana App
- Hazelcast
jet_demo
App - Hazelcast
perf_test
App - Hazelcast WAN Example
- Hazelcast Workspaces on VMs
- Hazelcast on AWS EC2
- Reactivating Hazelcast Workspaces on AWS EC2
ComputeDB/SnappyData
Coherence
Hadoop
Kafka/Confluent
Mosquitto
- Mosquitto CLASSPATH
- Mosquitto Overview
- Installing/Building Mosquitto
- Clustering MQTT
- Cluster Archetypes
- Enabling Mosquitto SSL/TLS
- Mosquitto Docker Compose
- MQTT perf_test App
Redis
Spark