Blazingly fast multi-language serialization framework powered by JIT and zero-copy
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Apache Fury's extensible serializer framework allows for custom serialization logic, specialized type handling, and performance optimizations for specific use cases.
Base abstract class for all custom serializers.
public abstract class Serializer<T> {
// Core serialization methods
public abstract void write(MemoryBuffer buffer, T value);
public abstract T read(MemoryBuffer buffer);
// Type information
public abstract Class<T> getType();
public short getTypeId();
// Reference tracking
public boolean needToWriteRef();
public void setNeedToWriteRef(boolean needToWriteRef);
// Cross-language support
public boolean supportCodegenHook();
public String codecgen(CodegenContext context);
// Lifecycle methods
public void setFury(Fury fury);
public Fury getFury();
}Base class for object serializers with field-based serialization.
public abstract class AbstractObjectSerializer<T> extends Serializer<T> {
// Field-based serialization support
protected void writeFields(MemoryBuffer buffer, T obj);
protected T readFields(MemoryBuffer buffer, T obj);
// Object creation
protected T newInstance();
protected T newInstance(Class<?> clazz);
// Field access
protected Object getFieldValue(Object obj, String fieldName);
protected void setFieldValue(Object obj, String fieldName, Object value);
}Base class for code-generated serializers providing optimal performance.
public abstract class CodegenSerializer<T> extends Serializer<T> {
// Generated serialization methods
@Override
public void write(MemoryBuffer buffer, T value);
@Override
public T read(MemoryBuffer buffer);
// Code generation support
public static String genCode(Class<?> clazz, CodegenContext context);
}Serializer supporting schema evolution and backward compatibility.
public abstract class CompatibleSerializer<T> extends AbstractObjectSerializer<T> {
// Schema compatibility support
protected void writeTypeAndObject(MemoryBuffer buffer, T obj);
protected T readTypeAndObject(MemoryBuffer buffer);
// Schema evolution
protected boolean isSchemaCompatible(ClassDef classDef);
protected void handleSchemaEvolution(MemoryBuffer buffer, T obj, ClassDef classDef);
}Optimized serializer for immutable objects.
public abstract class ImmutableSerializer<T> extends Serializer<T> {
// Immutable object handling
@Override
public final boolean needToWriteRef();
// Optimized for immutable types
protected abstract T createInstance(Object... args);
}Base class for collection serializers.
public abstract class AbstractCollectionSerializer<T> extends Serializer<T> {
// Collection serialization
protected void writeElements(MemoryBuffer buffer, Collection<?> collection);
protected Collection<Object> readElements(MemoryBuffer buffer, Collection<Object> collection);
// Collection metadata
protected void writeCollectionInfo(MemoryBuffer buffer, Collection<?> collection);
protected CollectionInfo readCollectionInfo(MemoryBuffer buffer);
// Element handling
protected void writeElement(MemoryBuffer buffer, Object element);
protected Object readElement(MemoryBuffer buffer);
}Base class for map serializers.
public abstract class AbstractMapSerializer<T> extends Serializer<T> {
// Map serialization
protected void writeKVs(MemoryBuffer buffer, Map<?, ?> map);
protected Map<Object, Object> readKVs(MemoryBuffer buffer, Map<Object, Object> map);
// Map metadata
protected void writeMapInfo(MemoryBuffer buffer, Map<?, ?> map);
protected MapInfo readMapInfo(MemoryBuffer buffer);
// Key-value handling
protected void writeKV(MemoryBuffer buffer, Object key, Object value);
protected Map.Entry<Object, Object> readKV(MemoryBuffer buffer);
}Factory for creating and managing serializers.
public class SerializerFactory {
// Serializer creation
public static <T> Serializer<T> createSerializer(Fury fury, Class<T> type);
public static <T> Serializer<T> createObjectSerializer(Fury fury, Class<T> type);
public static <T> Serializer<T> createCompatibleSerializer(Fury fury, Class<T> type);
// Built-in serializers
public static Serializer<?> createCollectionSerializer(Fury fury, Class<?> collectionType);
public static Serializer<?> createMapSerializer(Fury fury, Class<?> mapType);
public static Serializer<?> createArraySerializer(Fury fury, Class<?> arrayType);
// Serializer utilities
public static boolean canCreateSerializer(Class<?> type);
public static boolean needsCustomSerializer(Class<?> type);
}public class PrimitiveSerializers {
public static class BooleanSerializer extends Serializer<Boolean>;
public static class ByteSerializer extends Serializer<Byte>;
public static class ShortSerializer extends Serializer<Short>;
public static class IntSerializer extends Serializer<Integer>;
public static class LongSerializer extends Serializer<Long>;
public static class FloatSerializer extends Serializer<Float>;
public static class DoubleSerializer extends Serializer<Double>;
public static class CharSerializer extends Serializer<Character>;
}public class StringSerializer extends Serializer<String> {
// Optimized string serialization
@Override
public void write(MemoryBuffer buffer, String value);
@Override
public String read(MemoryBuffer buffer);
// String encoding options
public void setEncoding(Charset encoding);
public void setCompressed(boolean compressed);
}public class TimeSerializers {
public static class DateSerializer extends Serializer<Date>;
public static class TimestampSerializer extends Serializer<Timestamp>;
public static class InstantSerializer extends Serializer<Instant>;
public static class LocalDateSerializer extends Serializer<LocalDate>;
public static class LocalTimeSerializer extends Serializer<LocalTime>;
public static class LocalDateTimeSerializer extends Serializer<LocalDateTime>;
}import org.apache.fury.Fury;
import org.apache.fury.memory.MemoryBuffer;
import org.apache.fury.serializer.Serializer;
// Custom class to serialize
public class Point {
private double x, y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
// getters and setters...
}
// Custom serializer
public class PointSerializer extends Serializer<Point> {
@Override
public void write(MemoryBuffer buffer, Point point) {
buffer.writeDouble(point.getX());
buffer.writeDouble(point.getY());
}
@Override
public Point read(MemoryBuffer buffer) {
double x = buffer.readDouble();
double y = buffer.readDouble();
return new Point(x, y);
}
@Override
public Class<Point> getType() {
return Point.class;
}
}
// Register and use
Fury fury = Fury.builder().build();
fury.registerSerializer(Point.class, new PointSerializer());
// Serialization works with custom serializer
Point point = new Point(1.5, 2.5);
byte[] bytes = fury.serialize(point);
Point restored = (Point) fury.deserialize(bytes);import org.apache.fury.serializer.AbstractObjectSerializer;
public class UserSerializer extends AbstractObjectSerializer<User> {
@Override
public void write(MemoryBuffer buffer, User user) {
// Write fields in specific order
buffer.writeString(user.getName());
buffer.writeInt(user.getAge());
buffer.writeBoolean(user.isActive());
// Handle optional fields
if (user.getEmail() != null) {
buffer.writeBoolean(true);
buffer.writeString(user.getEmail());
} else {
buffer.writeBoolean(false);
}
// Serialize nested objects
getFury().writeRef(buffer, user.getAddress());
}
@Override
public User read(MemoryBuffer buffer) {
String name = buffer.readString();
int age = buffer.readInt();
boolean active = buffer.readBoolean();
// Handle optional fields
String email = null;
if (buffer.readBoolean()) {
email = buffer.readString();
}
// Deserialize nested objects
Address address = (Address) getFury().readRef(buffer);
return new User(name, age, active, email, address);
}
@Override
public Class<User> getType() {
return User.class;
}
}import org.apache.fury.serializer.AbstractCollectionSerializer;
public class CustomListSerializer extends AbstractCollectionSerializer<CustomList> {
@Override
public void write(MemoryBuffer buffer, CustomList list) {
// Write size
buffer.writeInt(list.size());
// Write custom metadata
buffer.writeString(list.getName());
buffer.writeBoolean(list.isSorted());
// Write elements
for (Object element : list) {
getFury().writeRef(buffer, element);
}
}
@Override
public CustomList read(MemoryBuffer buffer) {
int size = buffer.readInt();
String name = buffer.readString();
boolean sorted = buffer.readBoolean();
CustomList list = new CustomList(name, sorted);
// Read elements
for (int i = 0; i < size; i++) {
Object element = getFury().readRef(buffer);
list.add(element);
}
return list;
}
@Override
public Class<CustomList> getType() {
return CustomList.class;
}
}import org.apache.fury.serializer.ImmutableSerializer;
public class ImmutablePersonSerializer extends ImmutableSerializer<ImmutablePerson> {
@Override
public void write(MemoryBuffer buffer, ImmutablePerson person) {
buffer.writeString(person.getName());
buffer.writeInt(person.getAge());
buffer.writeString(person.getEmail());
}
@Override
public ImmutablePerson read(MemoryBuffer buffer) {
String name = buffer.readString();
int age = buffer.readInt();
String email = buffer.readString();
return ImmutablePerson.builder()
.name(name)
.age(age)
.email(email)
.build();
}
@Override
protected ImmutablePerson createInstance(Object... args) {
return ImmutablePerson.builder()
.name((String) args[0])
.age((Integer) args[1])
.email((String) args[2])
.build();
}
@Override
public Class<ImmutablePerson> getType() {
return ImmutablePerson.class;
}
}public class CustomEnumSerializer extends Serializer<MyEnum> {
@Override
public void write(MemoryBuffer buffer, MyEnum value) {
// Write enum ordinal for efficiency
buffer.writeInt(value.ordinal());
}
@Override
public MyEnum read(MemoryBuffer buffer) {
int ordinal = buffer.readInt();
return MyEnum.values()[ordinal];
}
@Override
public Class<MyEnum> getType() {
return MyEnum.class;
}
// Disable reference tracking for enums
@Override
public boolean needToWriteRef() {
return false;
}
}import org.apache.fury.serializer.CompatibleSerializer;
public class VersionedUserSerializer extends CompatibleSerializer<User> {
private static final int VERSION = 2;
@Override
public void write(MemoryBuffer buffer, User user) {
// Write version first
buffer.writeInt(VERSION);
// Write fields based on current version
buffer.writeString(user.getName());
buffer.writeInt(user.getAge());
if (VERSION >= 2) {
buffer.writeString(user.getEmail()); // Added in version 2
}
}
@Override
public User read(MemoryBuffer buffer) {
int version = buffer.readInt();
String name = buffer.readString();
int age = buffer.readInt();
String email = null;
if (version >= 2) {
email = buffer.readString();
}
return new User(name, age, email);
}
@Override
public Class<User> getType() {
return User.class;
}
}public class SerializerRegistration {
public static void registerCustomSerializers(Fury fury) {
// Register individual serializers
fury.registerSerializer(Point.class, new PointSerializer());
fury.registerSerializer(User.class, new UserSerializer());
// Register serializer class (instantiated by Fury)
fury.registerSerializer(CustomList.class, CustomListSerializer.class);
// Register with custom factory
fury.registerSerializer(ImmutablePerson.class,
(f) -> new ImmutablePersonSerializer());
}
}public class ConditionalSerializer extends Serializer<ConditionalObject> {
@Override
public void write(MemoryBuffer buffer, ConditionalObject obj) {
// Write discriminant
buffer.writeByte(obj.getType().ordinal());
// Conditional serialization based on type
switch (obj.getType()) {
case SIMPLE:
buffer.writeString(obj.getSimpleValue());
break;
case COMPLEX:
getFury().writeRef(buffer, obj.getComplexValue());
break;
case OPTIMIZED:
writeOptimizedFormat(buffer, obj);
break;
}
}
@Override
public ConditionalObject read(MemoryBuffer buffer) {
ObjectType type = ObjectType.values()[buffer.readByte()];
switch (type) {
case SIMPLE:
return new ConditionalObject(type, buffer.readString());
case COMPLEX:
return new ConditionalObject(type, getFury().readRef(buffer));
case OPTIMIZED:
return readOptimizedFormat(buffer);
default:
throw new IllegalStateException("Unknown type: " + type);
}
}
}public class OptimizedSerializer extends Serializer<LargeObject> {
// Cache field accessors for performance
private final FieldAccessor[] fieldAccessors;
public OptimizedSerializer() {
Field[] fields = ReflectionUtils.getFields(LargeObject.class);
fieldAccessors = new FieldAccessor[fields.length];
for (int i = 0; i < fields.length; i++) {
fieldAccessors[i] = FieldAccessor.createUnsafeAccessor(fields[i]);
}
}
@Override
public void write(MemoryBuffer buffer, LargeObject obj) {
// Use cached accessors for maximum performance
for (FieldAccessor accessor : fieldAccessors) {
Class<?> type = accessor.getType();
if (type == int.class) {
buffer.writeInt(accessor.getInt(obj));
} else if (type == String.class) {
buffer.writeString((String) accessor.get(obj));
}
// ... handle other types
}
}
@Override
public Class<LargeObject> getType() {
return LargeObject.class;
}
}Install with Tessl CLI
npx tessl i tessl/pypi-pyfury