or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

collections-utilities.mdconfiguration.mdcore-serialization.mdcustom-serializers.mdindex.mdmemory-management.mdsecurity.mdtype-system.md

custom-serializers.mddocs/

0

# Custom Serializers

1

2

Apache Fury's extensible serializer framework allows for custom serialization logic, specialized type handling, and performance optimizations for specific use cases.

3

4

## Serializer Base Classes

5

6

### Serializer

7

8

Base abstract class for all custom serializers.

9

10

```java { .api }

11

public abstract class Serializer<T> {

12

// Core serialization methods

13

public abstract void write(MemoryBuffer buffer, T value);

14

public abstract T read(MemoryBuffer buffer);

15

16

// Type information

17

public abstract Class<T> getType();

18

public short getTypeId();

19

20

// Reference tracking

21

public boolean needToWriteRef();

22

public void setNeedToWriteRef(boolean needToWriteRef);

23

24

// Cross-language support

25

public boolean supportCodegenHook();

26

public String codecgen(CodegenContext context);

27

28

// Lifecycle methods

29

public void setFury(Fury fury);

30

public Fury getFury();

31

}

32

```

33

34

### AbstractObjectSerializer

35

36

Base class for object serializers with field-based serialization.

37

38

```java { .api }

39

public abstract class AbstractObjectSerializer<T> extends Serializer<T> {

40

// Field-based serialization support

41

protected void writeFields(MemoryBuffer buffer, T obj);

42

protected T readFields(MemoryBuffer buffer, T obj);

43

44

// Object creation

45

protected T newInstance();

46

protected T newInstance(Class<?> clazz);

47

48

// Field access

49

protected Object getFieldValue(Object obj, String fieldName);

50

protected void setFieldValue(Object obj, String fieldName, Object value);

51

}

52

```

53

54

## Specialized Serializers

55

56

### CodegenSerializer

57

58

Base class for code-generated serializers providing optimal performance.

59

60

```java { .api }

61

public abstract class CodegenSerializer<T> extends Serializer<T> {

62

// Generated serialization methods

63

@Override

64

public void write(MemoryBuffer buffer, T value);

65

@Override

66

public T read(MemoryBuffer buffer);

67

68

// Code generation support

69

public static String genCode(Class<?> clazz, CodegenContext context);

70

}

71

```

72

73

### CompatibleSerializer

74

75

Serializer supporting schema evolution and backward compatibility.

76

77

```java { .api }

78

public abstract class CompatibleSerializer<T> extends AbstractObjectSerializer<T> {

79

// Schema compatibility support

80

protected void writeTypeAndObject(MemoryBuffer buffer, T obj);

81

protected T readTypeAndObject(MemoryBuffer buffer);

82

83

// Schema evolution

84

protected boolean isSchemaCompatible(ClassDef classDef);

85

protected void handleSchemaEvolution(MemoryBuffer buffer, T obj, ClassDef classDef);

86

}

87

```

88

89

### ImmutableSerializer

90

91

Optimized serializer for immutable objects.

92

93

```java { .api }

94

public abstract class ImmutableSerializer<T> extends Serializer<T> {

95

// Immutable object handling

96

@Override

97

public final boolean needToWriteRef();

98

99

// Optimized for immutable types

100

protected abstract T createInstance(Object... args);

101

}

102

```

103

104

## Collection Serializers

105

106

### AbstractCollectionSerializer

107

108

Base class for collection serializers.

109

110

```java { .api }

111

public abstract class AbstractCollectionSerializer<T> extends Serializer<T> {

112

// Collection serialization

113

protected void writeElements(MemoryBuffer buffer, Collection<?> collection);

114

protected Collection<Object> readElements(MemoryBuffer buffer, Collection<Object> collection);

115

116

// Collection metadata

117

protected void writeCollectionInfo(MemoryBuffer buffer, Collection<?> collection);

118

protected CollectionInfo readCollectionInfo(MemoryBuffer buffer);

119

120

// Element handling

121

protected void writeElement(MemoryBuffer buffer, Object element);

122

protected Object readElement(MemoryBuffer buffer);

123

}

124

```

125

126

### AbstractMapSerializer

127

128

Base class for map serializers.

129

130

```java { .api }

131

public abstract class AbstractMapSerializer<T> extends Serializer<T> {

132

// Map serialization

133

protected void writeKVs(MemoryBuffer buffer, Map<?, ?> map);

134

protected Map<Object, Object> readKVs(MemoryBuffer buffer, Map<Object, Object> map);

135

136

// Map metadata

137

protected void writeMapInfo(MemoryBuffer buffer, Map<?, ?> map);

138

protected MapInfo readMapInfo(MemoryBuffer buffer);

139

140

// Key-value handling

141

protected void writeKV(MemoryBuffer buffer, Object key, Object value);

142

protected Map.Entry<Object, Object> readKV(MemoryBuffer buffer);

143

}

144

```

145

146

## Serializer Factory

147

148

Factory for creating and managing serializers.

149

150

```java { .api }

151

public class SerializerFactory {

152

// Serializer creation

153

public static <T> Serializer<T> createSerializer(Fury fury, Class<T> type);

154

public static <T> Serializer<T> createObjectSerializer(Fury fury, Class<T> type);

155

public static <T> Serializer<T> createCompatibleSerializer(Fury fury, Class<T> type);

156

157

// Built-in serializers

158

public static Serializer<?> createCollectionSerializer(Fury fury, Class<?> collectionType);

159

public static Serializer<?> createMapSerializer(Fury fury, Class<?> mapType);

160

public static Serializer<?> createArraySerializer(Fury fury, Class<?> arrayType);

161

162

// Serializer utilities

163

public static boolean canCreateSerializer(Class<?> type);

164

public static boolean needsCustomSerializer(Class<?> type);

165

}

166

```

167

168

## Built-in Serializers

169

170

### Primitive Serializers

171

172

```java { .api }

173

public class PrimitiveSerializers {

174

public static class BooleanSerializer extends Serializer<Boolean>;

175

public static class ByteSerializer extends Serializer<Byte>;

176

public static class ShortSerializer extends Serializer<Short>;

177

public static class IntSerializer extends Serializer<Integer>;

178

public static class LongSerializer extends Serializer<Long>;

179

public static class FloatSerializer extends Serializer<Float>;

180

public static class DoubleSerializer extends Serializer<Double>;

181

public static class CharSerializer extends Serializer<Character>;

182

}

183

```

184

185

### String Serializers

186

187

```java { .api }

188

public class StringSerializer extends Serializer<String> {

189

// Optimized string serialization

190

@Override

191

public void write(MemoryBuffer buffer, String value);

192

@Override

193

public String read(MemoryBuffer buffer);

194

195

// String encoding options

196

public void setEncoding(Charset encoding);

197

public void setCompressed(boolean compressed);

198

}

199

```

200

201

### Time Serializers

202

203

```java { .api }

204

public class TimeSerializers {

205

public static class DateSerializer extends Serializer<Date>;

206

public static class TimestampSerializer extends Serializer<Timestamp>;

207

public static class InstantSerializer extends Serializer<Instant>;

208

public static class LocalDateSerializer extends Serializer<LocalDate>;

209

public static class LocalTimeSerializer extends Serializer<LocalTime>;

210

public static class LocalDateTimeSerializer extends Serializer<LocalDateTime>;

211

}

212

```

213

214

## Usage Examples

215

216

### Creating Custom Serializers

217

218

```java

219

import org.apache.fury.Fury;

220

import org.apache.fury.memory.MemoryBuffer;

221

import org.apache.fury.serializer.Serializer;

222

223

// Custom class to serialize

224

public class Point {

225

private double x, y;

226

227

public Point(double x, double y) {

228

this.x = x;

229

this.y = y;

230

}

231

232

// getters and setters...

233

}

234

235

// Custom serializer

236

public class PointSerializer extends Serializer<Point> {

237

@Override

238

public void write(MemoryBuffer buffer, Point point) {

239

buffer.writeDouble(point.getX());

240

buffer.writeDouble(point.getY());

241

}

242

243

@Override

244

public Point read(MemoryBuffer buffer) {

245

double x = buffer.readDouble();

246

double y = buffer.readDouble();

247

return new Point(x, y);

248

}

249

250

@Override

251

public Class<Point> getType() {

252

return Point.class;

253

}

254

}

255

256

// Register and use

257

Fury fury = Fury.builder().build();

258

fury.registerSerializer(Point.class, new PointSerializer());

259

260

// Serialization works with custom serializer

261

Point point = new Point(1.5, 2.5);

262

byte[] bytes = fury.serialize(point);

263

Point restored = (Point) fury.deserialize(bytes);

264

```

265

266

### Complex Object Serializer

267

268

```java

269

import org.apache.fury.serializer.AbstractObjectSerializer;

270

271

public class UserSerializer extends AbstractObjectSerializer<User> {

272

@Override

273

public void write(MemoryBuffer buffer, User user) {

274

// Write fields in specific order

275

buffer.writeString(user.getName());

276

buffer.writeInt(user.getAge());

277

buffer.writeBoolean(user.isActive());

278

279

// Handle optional fields

280

if (user.getEmail() != null) {

281

buffer.writeBoolean(true);

282

buffer.writeString(user.getEmail());

283

} else {

284

buffer.writeBoolean(false);

285

}

286

287

// Serialize nested objects

288

getFury().writeRef(buffer, user.getAddress());

289

}

290

291

@Override

292

public User read(MemoryBuffer buffer) {

293

String name = buffer.readString();

294

int age = buffer.readInt();

295

boolean active = buffer.readBoolean();

296

297

// Handle optional fields

298

String email = null;

299

if (buffer.readBoolean()) {

300

email = buffer.readString();

301

}

302

303

// Deserialize nested objects

304

Address address = (Address) getFury().readRef(buffer);

305

306

return new User(name, age, active, email, address);

307

}

308

309

@Override

310

public Class<User> getType() {

311

return User.class;

312

}

313

}

314

```

315

316

### Collection Serializer

317

318

```java

319

import org.apache.fury.serializer.AbstractCollectionSerializer;

320

321

public class CustomListSerializer extends AbstractCollectionSerializer<CustomList> {

322

@Override

323

public void write(MemoryBuffer buffer, CustomList list) {

324

// Write size

325

buffer.writeInt(list.size());

326

327

// Write custom metadata

328

buffer.writeString(list.getName());

329

buffer.writeBoolean(list.isSorted());

330

331

// Write elements

332

for (Object element : list) {

333

getFury().writeRef(buffer, element);

334

}

335

}

336

337

@Override

338

public CustomList read(MemoryBuffer buffer) {

339

int size = buffer.readInt();

340

String name = buffer.readString();

341

boolean sorted = buffer.readBoolean();

342

343

CustomList list = new CustomList(name, sorted);

344

345

// Read elements

346

for (int i = 0; i < size; i++) {

347

Object element = getFury().readRef(buffer);

348

list.add(element);

349

}

350

351

return list;

352

}

353

354

@Override

355

public Class<CustomList> getType() {

356

return CustomList.class;

357

}

358

}

359

```

360

361

### Immutable Object Serializer

362

363

```java

364

import org.apache.fury.serializer.ImmutableSerializer;

365

366

public class ImmutablePersonSerializer extends ImmutableSerializer<ImmutablePerson> {

367

@Override

368

public void write(MemoryBuffer buffer, ImmutablePerson person) {

369

buffer.writeString(person.getName());

370

buffer.writeInt(person.getAge());

371

buffer.writeString(person.getEmail());

372

}

373

374

@Override

375

public ImmutablePerson read(MemoryBuffer buffer) {

376

String name = buffer.readString();

377

int age = buffer.readInt();

378

String email = buffer.readString();

379

380

return ImmutablePerson.builder()

381

.name(name)

382

.age(age)

383

.email(email)

384

.build();

385

}

386

387

@Override

388

protected ImmutablePerson createInstance(Object... args) {

389

return ImmutablePerson.builder()

390

.name((String) args[0])

391

.age((Integer) args[1])

392

.email((String) args[2])

393

.build();

394

}

395

396

@Override

397

public Class<ImmutablePerson> getType() {

398

return ImmutablePerson.class;

399

}

400

}

401

```

402

403

### Enum Serializer

404

405

```java

406

public class CustomEnumSerializer extends Serializer<MyEnum> {

407

@Override

408

public void write(MemoryBuffer buffer, MyEnum value) {

409

// Write enum ordinal for efficiency

410

buffer.writeInt(value.ordinal());

411

}

412

413

@Override

414

public MyEnum read(MemoryBuffer buffer) {

415

int ordinal = buffer.readInt();

416

return MyEnum.values()[ordinal];

417

}

418

419

@Override

420

public Class<MyEnum> getType() {

421

return MyEnum.class;

422

}

423

424

// Disable reference tracking for enums

425

@Override

426

public boolean needToWriteRef() {

427

return false;

428

}

429

}

430

```

431

432

### Versioned Serializer

433

434

```java

435

import org.apache.fury.serializer.CompatibleSerializer;

436

437

public class VersionedUserSerializer extends CompatibleSerializer<User> {

438

private static final int VERSION = 2;

439

440

@Override

441

public void write(MemoryBuffer buffer, User user) {

442

// Write version first

443

buffer.writeInt(VERSION);

444

445

// Write fields based on current version

446

buffer.writeString(user.getName());

447

buffer.writeInt(user.getAge());

448

449

if (VERSION >= 2) {

450

buffer.writeString(user.getEmail()); // Added in version 2

451

}

452

}

453

454

@Override

455

public User read(MemoryBuffer buffer) {

456

int version = buffer.readInt();

457

458

String name = buffer.readString();

459

int age = buffer.readInt();

460

461

String email = null;

462

if (version >= 2) {

463

email = buffer.readString();

464

}

465

466

return new User(name, age, email);

467

}

468

469

@Override

470

public Class<User> getType() {

471

return User.class;

472

}

473

}

474

```

475

476

### Serializer Registration

477

478

```java

479

public class SerializerRegistration {

480

public static void registerCustomSerializers(Fury fury) {

481

// Register individual serializers

482

fury.registerSerializer(Point.class, new PointSerializer());

483

fury.registerSerializer(User.class, new UserSerializer());

484

485

// Register serializer class (instantiated by Fury)

486

fury.registerSerializer(CustomList.class, CustomListSerializer.class);

487

488

// Register with custom factory

489

fury.registerSerializer(ImmutablePerson.class,

490

(f) -> new ImmutablePersonSerializer());

491

}

492

}

493

```

494

495

## Advanced Patterns

496

497

### Conditional Serialization

498

499

```java

500

public class ConditionalSerializer extends Serializer<ConditionalObject> {

501

@Override

502

public void write(MemoryBuffer buffer, ConditionalObject obj) {

503

// Write discriminant

504

buffer.writeByte(obj.getType().ordinal());

505

506

// Conditional serialization based on type

507

switch (obj.getType()) {

508

case SIMPLE:

509

buffer.writeString(obj.getSimpleValue());

510

break;

511

case COMPLEX:

512

getFury().writeRef(buffer, obj.getComplexValue());

513

break;

514

case OPTIMIZED:

515

writeOptimizedFormat(buffer, obj);

516

break;

517

}

518

}

519

520

@Override

521

public ConditionalObject read(MemoryBuffer buffer) {

522

ObjectType type = ObjectType.values()[buffer.readByte()];

523

524

switch (type) {

525

case SIMPLE:

526

return new ConditionalObject(type, buffer.readString());

527

case COMPLEX:

528

return new ConditionalObject(type, getFury().readRef(buffer));

529

case OPTIMIZED:

530

return readOptimizedFormat(buffer);

531

default:

532

throw new IllegalStateException("Unknown type: " + type);

533

}

534

}

535

}

536

```

537

538

### Performance Optimizations

539

540

```java

541

public class OptimizedSerializer extends Serializer<LargeObject> {

542

// Cache field accessors for performance

543

private final FieldAccessor[] fieldAccessors;

544

545

public OptimizedSerializer() {

546

Field[] fields = ReflectionUtils.getFields(LargeObject.class);

547

fieldAccessors = new FieldAccessor[fields.length];

548

for (int i = 0; i < fields.length; i++) {

549

fieldAccessors[i] = FieldAccessor.createUnsafeAccessor(fields[i]);

550

}

551

}

552

553

@Override

554

public void write(MemoryBuffer buffer, LargeObject obj) {

555

// Use cached accessors for maximum performance

556

for (FieldAccessor accessor : fieldAccessors) {

557

Class<?> type = accessor.getType();

558

if (type == int.class) {

559

buffer.writeInt(accessor.getInt(obj));

560

} else if (type == String.class) {

561

buffer.writeString((String) accessor.get(obj));

562

}

563

// ... handle other types

564

}

565

}

566

567

@Override

568

public Class<LargeObject> getType() {

569

return LargeObject.class;

570

}

571

}

572

```

573

574

## Performance Considerations

575

576

### Serializer Design

577

578

- **Minimize Object Creation**: Reuse objects and avoid unnecessary allocations

579

- **Use Primitive Operations**: Access primitive fields directly for better performance

580

- **Cache Metadata**: Cache field accessors and type information

581

- **Optimize Hot Paths**: Focus on frequently serialized types

582

583

### Registration Strategy

584

585

- **Register Early**: Register serializers during application startup

586

- **Use Type IDs**: Assign explicit type IDs for better performance

587

- **Batch Registration**: Register related serializers together

588

- **Monitor Performance**: Profile serialization hotspots

589

590

### Memory Efficiency

591

592

- **Compact Formats**: Use efficient binary representations

593

- **Avoid Boxing**: Work with primitives when possible

594

- **Reference Management**: Carefully manage reference tracking needs

595

- **Buffer Usage**: Minimize buffer allocations and copies