Releases: apache/fory
Release list
v1.3.0
Highlights
- Python gRPC code generation now defaults to the
grpc.aioAsyncIO API, while synchronousgrpciooutput remains available through--grpc-python-mode=sync. - Dart joins the generated gRPC service surface:
foryc --dart_out=... --grpcnow emitspackage:grpcclients, service bases, method descriptors, and Fory-backed payload serialization. - Compiler gRPC documentation was refined across languages, including clearer guidance for generated service dependencies and transport behavior.
- Runtime hardening continued with remote schema metadata limits and Java aligned-varint/type-checker fixes.
Python Async gRPC Mode
Python gRPC generation now targets AsyncIO by default. Generated companions use
grpc.aio: servicer bases expose async def methods, stubs are used with
grpc.aio.Channel instances, and streaming RPCs use async iterables. This keeps
the generated code aligned with modern Python async services while preserving
the same Fory-backed request and response encoding used by the existing gRPC
support.
Generate the default async companion with:
foryc service.fdl --python_out=./generated/python --grpcFor a simple unary service, the generated async server shape is:
import asyncio
import grpc.aio
import demo_greeter
import demo_greeter_grpc
class Greeter(demo_greeter_grpc.GreeterServicer):
async def say_hello(self, request, context):
return demo_greeter.HelloReply(reply=f"Hello, {request.name}")
async def serve():
server = grpc.aio.server()
demo_greeter_grpc.add_servicer(Greeter(), server)
server.add_insecure_port("[::]:50051")
await server.start()
await server.wait_for_termination()
asyncio.run(serve())Clients use a grpc.aio channel and await generated stub methods:
import grpc
import grpc.aio
import demo_greeter
import demo_greeter_grpc
credentials = grpc.ssl_channel_credentials()
async with grpc.aio.secure_channel("api.example.com:443", credentials) as channel:
stub = demo_greeter_grpc.GreeterStub(channel)
reply = await stub.say_hello(demo_greeter.HelloRequest(name="Fory"))Existing synchronous applications can still request sync companions explicitly:
foryc service.fdl --python_out=./generated/python --grpc --grpc-python-mode=syncIn sync mode the generated public names and <module>_grpc.py filename stay the
same, but applications use grpc.server(...), standard grpc.Channel
instances, and regular def servicer methods.
Dart gRPC Code Generation
Fory 1.3.0 adds Dart gRPC service generation for schemas with service
definitions. Service definitions can come from Fory IDL, protobuf IDL, or
FlatBuffers rpc_service definitions. The generated code uses normal
grpc-dart APIs for clients, service bases, method descriptors, call options,
deadlines, cancellations, metadata, and status codes, while each request and
response object is serialized with Fory instead of protobuf message bytes.
Add grpc and build_runner alongside the Fory package in the Dart
application:
dependencies:
fory: ^1.3.0
grpc: ^4.0.0
dev_dependencies:
build_runner: ^2.4.0Generate Dart models and the gRPC companion with:
foryc service.fdl --dart_out=./lib/generated --grpc
dart run build_runner build --delete-conflicting-outputsFor a demo.greeter package, the generator emits the model file, the
build_runner serializer part, and a <stem>_grpc.dart companion with
GreeterServiceBase and GreeterClient. The generated client and service base
install the schema's Fory module automatically on first use, so service
implementations do not need a separate manual registration step for the
generated message types.
A unary Dart server uses grpc-dart's Server and the generated service base:
import 'dart:io';
import 'package:grpc/grpc.dart';
import 'demo/greeter/greeter.dart';
import 'demo/greeter/greeter_grpc.dart';
class GreeterService extends GreeterServiceBase {
@override
Future<HelloReply> sayHello(ServiceCall call, HelloRequest request) async {
return HelloReply()..reply = 'Hello, ${request.name}';
}
}
Future<void> main() async {
final server = Server.create(services: [GreeterService()]);
await server.serve(address: InternetAddress.loopbackIPv4, port: 50051);
}Generated Dart clients use standard ClientChannel values and return the
grpc-dart call types:
import 'package:grpc/grpc.dart';
import 'demo/greeter/greeter.dart';
import 'demo/greeter/greeter_grpc.dart';
final channel = ClientChannel(
'localhost',
port: 50051,
options: const ChannelOptions(credentials: ChannelCredentials.insecure()),
);
final client = GreeterClient(channel);
final reply = await client.sayHello(HelloRequest()..name = 'Fory');
await channel.shutdown();Dart generation covers unary, server-streaming, client-streaming, and
bidirectional streaming RPC shapes following grpc-dart conventions.
Features
- feat(python): add async grpc mode for python by @chaokunyang in #3768
- feat: limit remote schema metadata by @chaokunyang in #3770
- feat(compiler): add dart gRPC codegen by @yash-agarwa-l in #3723
Bug Fix
- fix(java): guard aligned varint unsafe read by @chaokunyang in #3772
- fix(java): cache accepted type checker classes by @chaokunyang in #3773
Other Improvements
- docs: refine gRPC support guides by @chaokunyang in #3767
- docs: add threat model + SECURITY.md/AGENTS.md discoverability by @potiuk in #3734
- chore(release): enforce OpenJDK 25 for JVM publishing by @chaokunyang in #3775
New Contributors
Full Changelog: v1.2.0...v1.3.0
v1.3.0-rc1
Highlights
- feat(python): add async grpc mode for python by @chaokunyang in #3768
- feat(compiler): add dart gRPC codegen by @yash-agarwa-l in #3723
Features
- feat(python): add async grpc mode for python by @chaokunyang in #3768
- feat: limit remote schema metadata by @chaokunyang in #3770
- feat(compiler): add dart gRPC codegen by @yash-agarwa-l in #3723
Bug Fix
- fix(java): guard aligned varint unsafe read by @chaokunyang in #3772
- fix(java): cache accepted type checker classes by @chaokunyang in #3773
Other Improvements
- docs: refine gRPC support guides by @chaokunyang in #3767
- docs: add threat model + SECURITY.md/AGENTS.md discoverability by @potiuk in #3734
- chore(release): enforce OpenJDK 25 for JVM publishing by @chaokunyang in #3775
New Contributors
Full Changelog: v1.2.0...v1.3.0-rc1
v1.2.0
Highlights
- Expanded generated gRPC support across Go, Rust, Kotlin, Scala, C#, and JavaScript, including Node.js and browser gRPC-Web support for JavaScript.
- Improved cross-language compatibility with refined register-by-name APIs, compatible scalar read conversions, and default compatible mode for native serialization.
- Strengthened Java platform support by adding Java 9/16 module-info generation and removing
sun.misc.Unsafeusage for JDK 25. - Improved runtime safety and robustness with additional read checks, deflater leak fixes, and safer serializer/type-info error handling.
- Optimized compatible-mode and row-format performance through faster compatible reads, compact row layout caching, and inlined custom-codec dispatch.
- Enhanced compiler output quality across Rust, C++, and service generation with better identifier escaping, name-collision handling, nested container reference handling, and map code generation.
Java 25+ Without sun.misc.Unsafe
JDK 25 continues the platform shift away from sun.misc.Unsafe. Fory 1.2.0
adds a Java 25 multi-release runtime path so applications can run on JDK 25+
without resolving sun.misc.Unsafe from Fory's active class graph.
Older JDKs keep the existing fast paths. On JDK 25+, Fory uses replacement
classes backed by supported JVM mechanisms such as VarHandle, MethodHandle,
arrays, and ByteBuffer. Classes that previously depended on constructor
bypassing should provide an accessible no-arg constructor, use records, or
register a custom serializer.
Compatible Scalar Field Reads
Compatible mode already allows readers and writers to add, remove, and reorder
fields. Fory 1.2.0 extends that model to selected scalar type changes: when a
matched top-level field changes between boolean, string, numeric, and decimal
types, the reader can deserialize the value if the conversion is lossless.
Examples include reading "123" as an integer field, reading 1 or 0 as a
boolean field, reading booleans as 1/0, reading numbers or decimals as
canonical strings, and widening or narrowing numeric values only when no range
or precision is lost. Invalid strings, out-of-range values, lossy float/integer
conversions, and reference-tracked scalar type changes fail during
deserialization. The conversion applies to matched compatible fields, not to
root values or collection elements.
The examples below show Rust and Java using an int64 writer field and a
String reader field. The same compatible scalar field conversion is supported
across Fory's compatible-mode runtimes: Java, Python, Rust, C++, Go, C#, Swift,
Dart, JavaScript/TypeScript, Kotlin, and Scala. Compatible mode is enabled by
default in the Java and Python runtimes for both xlang and native serialization.
Rust example:
use fory::{Fory, ForyStruct};
#[derive(ForyStruct)]
struct MetricV1 {
value: i64,
}
#[derive(ForyStruct)]
struct MetricV2 {
value: String,
}
let mut writer = Fory::builder().xlang(true).compatible(true).build();
writer.register_by_name::<MetricV1>("example.Metric")?;
let mut reader = Fory::builder().xlang(true).compatible(true).build();
reader.register_by_name::<MetricV2>("example.Metric")?;
let bytes = writer.serialize(&MetricV1 { value: 42 })?;
let value: MetricV2 = reader.deserialize(&bytes)?;
assert_eq!(value.value, "42");Java example:
public class MetricV1 {
public long value;
}
public class MetricV2 {
public String value;
}
Fory writer = Fory.builder().withXlang(true).withCompatible(true).build();
writer.register(MetricV1.class, "example", "Metric");
Fory reader = Fory.builder().withXlang(true).withCompatible(true).build();
reader.register(MetricV2.class, "example", "Metric");
MetricV1 source = new MetricV1();
source.value = 42L;
byte[] bytes = writer.serialize(source);
MetricV2 value = reader.deserialize(bytes, MetricV2.class);
assert value.value.equals("42");The same rule works in the other direction, for example reading a String
field value such as "42" as int64, when the string uses Fory's strict
finite decimal grammar and the target range can represent the value exactly.
Generated gRPC Support
Fory 1.2.0 expands compiler-generated gRPC service companions. The generated
services use standard gRPC transports, channels, deadlines, metadata,
interceptors, status codes, and streaming shapes, while request and response
objects are encoded with Fory instead of protobuf message bytes. Use this mode
when both sides of the RPC are generated from the same Fory IDL, protobuf IDL,
or FlatBuffers IDL and you want gRPC operational semantics with Fory payload
encoding.
Generated gRPC support now covers Java, Python, Go, Rust, C#, Scala, Kotlin,
and JavaScript/TypeScript. JavaScript includes Node.js gRPC support and browser
gRPC-Web client generation. Only Rust and Java snippets are shown below; the
other supported languages provide the same Fory-backed service companion model
without duplicating code here.
The examples below use this shared schema:
package demo.greeter;
message HelloRequest {
string name = 1;
}
message HelloReply {
string reply = 1;
}
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}Rust generation emits tonic-based service API and binding modules:
use demo_greeter::{HelloReply, HelloRequest};
use demo_greeter_service::Greeter;
use demo_greeter_service_grpc::greeter_client::GreeterClient;
use demo_greeter_service_grpc::greeter_server::GreeterServer;
tonic::transport::Server::builder()
.add_service(GreeterServer::new(MyGreeter::default()))
.serve(addr)
.await?;
let mut client = GreeterClient::connect("http://[::1]:50051").await?;
let reply = client.say_hello(HelloRequest { name: "Fory".into() }).await?;Java generation emits grpc-java service bases, stubs, and Fory codecs:
final class GreeterService extends GreeterGrpc.GreeterImplBase {
@Override
public void sayHello(
HelloRequest request, StreamObserver<HelloReply> responseObserver) {
HelloReply reply = new HelloReply();
reply.setReply("Hello, " + request.getName());
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}
Server server = ServerBuilder.forPort(50051)
.addService(new GreeterService())
.build()
.start();
GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(channel);
HelloRequest request = new HelloRequest();
request.setName("Fory");
HelloReply reply = stub.sayHello(request);The generated gRPC companions intentionally do not make gRPC a hard dependency
of the core Fory language packages. Applications add the transport libraries
they use: grpc-java for Java and Scala, grpcio for Python, grpc-go for Go,
tonic/bytes for Rust, .NET gRPC packages for C#, @grpc/grpc-js or
grpc-web for JavaScript, and grpc-java/grpc-kotlin for Kotlin.
Features
- feat(java): add java9/16 module-info support by @chaokunyang in #3721
- refactor(format): inline custom-codec dispatch in row codecs by @stevenschlansker in #3716
- perf(format): cache compact row layout per nested slot by @stevenschlansker in #3717
- feat(java): remove sun.misc.Unsafe for jdk25 by @chaokunyang in #3702
- feat(rust): support thread safe
Arc<dyn Any + Send + Sync>type by @chaokunyang in #3736 - refactor(rust): refactor sync send type by @chaokunyang in #3737
- feat(xlang): refine register by name api by @chaokunyang in #3739
- feat(xlang): support compatible scalar read conversions by @chaokunyang in #3740
- feat: default compatible mode for native serialization by @chaokunyang in #3742
- perf: optimize compatible mode read performance by @chaokunyang in #3743
- feat(compiler): handle Rust identifier escaping and name collisions by @BaldDemian in #3744
- feat(go): implement grpc stub generation by @ayush00git in #3698
- refactor(compiler): generate C++ unordered map for Fory map by @BaldDemian in #3745
- feat(compiler): handle nested container ref pointer options in C++ compiler correctly by @BaldDemian in #3735
- feat: add more read checks by @chaokunyang in #3748
- feat(compiler): support Rust gRPC code generation by @BaldDemian in #3738
- feat(cpp): support struct property accessors by @chaokunyang in #3751
- feat(python): make scalar wire markers typing-friendly by @chaokunyang in #3756
- feat(kotlin): add kotlin grpc support by @chaokunyang in #3757
- feat(rust): make fory-derive generated code use exported api in fory rust lib by @chaokunyang in #3759
- feat(scala): add generated grpc service support for scala by @chaokunyang in #3762
- feat(csharp): add generated grpc support for C# by @chaokunyang in #3761
- feat(javascript): add javascript gRPC support for nodejs/browser by @chaokunyang in #3760
Bug Fix
- fix(go): return nil serializer on getTypeInfo err by @ayush00git in #3719
- fix(benchmarks): uses outdated google-java-format, upgrade spotless by @stevenschlansker in ht...
v1.2.0-rc1
Highlights
- Expanded generated gRPC support across Go, Rust, Kotlin, Scala, C#, and JavaScript, including Node.js and browser gRPC-Web support for JavaScript.
- Improved cross-language compatibility with refined register-by-name APIs, compatible scalar read conversions, and default compatible mode for native serialization.
- Strengthened Java platform support by adding Java 9/16 module-info generation and removing
sun.misc.Unsafeusage for JDK 25. - Improved runtime safety and robustness with additional read checks, deflater leak fixes, and safer serializer/type-info error handling.
- Optimized compatible-mode and row-format performance through faster compatible reads, compact row layout caching, and inlined custom-codec dispatch.
- Enhanced compiler output quality across Rust, C++, and service generation with better identifier escaping, name-collision handling, nested container reference handling, and map code generation.
Features
- feat(java): add java9/16 module-info support by @chaokunyang in #3721
- refactor(format): inline custom-codec dispatch in row codecs by @stevenschlansker in #3716
- perf(format): cache compact row layout per nested slot by @stevenschlansker in #3717
- feat(java): remove sun.misc.Unsafe for jdk25 by @chaokunyang in #3702
- feat(rust): support thread safe
Arc<dyn Any + Send + Sync>type by @chaokunyang in #3736 - refactor(rust): refactor sync send type by @chaokunyang in #3737
- feat(xlang): refine register by name api by @chaokunyang in #3739
- feat(xlang): support compatible scalar read conversions by @chaokunyang in #3740
- feat: default compatible mode for native serialization by @chaokunyang in #3742
- perf: optimize compatible mode read performance by @chaokunyang in #3743
- feat(compiler): handle Rust identifier escaping and name collisions by @BaldDemian in #3744
- feat(go): implement grpc stub generation by @ayush00git in #3698
- refactor(compiler): generate C++ unordered map for Fory map by @BaldDemian in #3745
- feat(compiler): handle nested container ref pointer options in C++ compiler correctly by @BaldDemian in #3735
- feat: add more read checks by @chaokunyang in #3748
- feat(compiler): support Rust gRPC code generation by @BaldDemian in #3738
- feat(cpp): support struct property accessors by @chaokunyang in #3751
- feat(python): make scalar wire markers typing-friendly by @chaokunyang in #3756
- feat(kotlin): add kotlin grpc support by @chaokunyang in #3757
- feat(rust): make fory-derive generated code use exported api in fory rust lib by @chaokunyang in #3759
- feat(scala): add generated grpc service support for scala by @chaokunyang in #3762
- feat(csharp): add generated grpc support for C# by @chaokunyang in #3761
- feat(javascript): add javascript gRPC support for nodejs/browser by @chaokunyang in #3760
Bug Fix
- fix(go): return nil serializer on getTypeInfo err by @ayush00git in #3719
- fix(benchmarks): uses outdated google-java-format, upgrade spotless by @stevenschlansker in #3722
- fix(format): pass row body size, not full payload size, to BinaryRow.pointTo by @stevenschlansker in #3715
- fix(java): fix deflater memory leak by @MNTMDEV in #3726
- fix(compiler): handle nested container ref pointer options in Rust compiler correctly by @BaldDemian in #3731
- fix(java): ignore non-Scala/Lombok-style default helper methods by @mandrean in #3733
- fix(c++): std::unordered_map cannot be used in struct. (#3727) by @ruoruoniao in #3728
- fix(grpc): fix rust/go grpc support by @chaokunyang in #3753
- fix(cpp): align unsigned struct default encoding by @chaokunyang in #3754
Other Improvements
- chore(deps): fix vulnerable dependencies by @chaokunyang in #3741
- chore: Bump MessagePack from 2.5.187 to 2.5.301 by @dependabot[bot] in #3750
- chore(deps): bump Go gRPC test dependencies by @chaokunyang in #3763
New Contributors
- @MNTMDEV made their first contribution in #3726
- @ruoruoniao made their first contribution in #3728
Full Changelog: v1.1.0...v1.2.0-rc1
v1.1.0
Highlights
- Added Java/Python gRPC support in the compiler.
- Improved xlang union handling with unknown union case support and sealed record generation for C# unions.
Features
- feat(compiler): add java/python gRPC support by @chaokunyang in #3692
- refactor(csharp): split Fory object attributes by @chaokunyang in #3709
- feat(c#): use sealed record for c# union by @chaokunyang in #3710
- feat(xlang): support unknown union case in union type by @chaokunyang in #3711
- refactor(compiler): rename generated schema owners to modules by @chaokunyang in #3713
Bug Fix
- fix(c++): propagate /Zc:preprocessor on MSVC for FORY_STRUCT consumers by @truffle-dev in #3694
- fix(cpp): repair CMake tests and examples by @chaokunyang in #3699
- fix(java): guard replace-resolve class reads by @chaokunyang in #3706
- fix(python): make policy validators validation-only by @chaokunyang in #3708
Other Improvements
- docs(cpp): clarify MSVC preprocessor requirement by @chaokunyang in #3695
- chore(deps): bump io.grpc:grpc-netty-shaded from 1.62.2 to 1.75.0 in /integration_tests/grpc_tests/java by @dependabot[bot] in #3697
- docs(xlang): update language support docs by @chaokunyang in #3700
- docs: fix xlang type mapping MDX by @chaokunyang in #3701
- chore(js): upgrade test dependencies by @chaokunyang in #3703
- ci: declare workflow-level
contents: readon ci and lint by @arpitjain099 in #3704 - docs: update readme to add android support by @chaokunyang in #3705
- chore: update java checks docs by @chaokunyang in #3707
New Contributors
- @truffle-dev made their first contribution in #3694
- @arpitjain099 made their first contribution in #3704
Full Changelog: v1.0.0...v1.1.0
v1.1.0-rc1
Highlights
- Added Java/Python gRPC support in the compiler.
- Improved xlang union handling with unknown union case support and sealed record generation for C# unions.
Features
- feat(compiler): add java/python gRPC support by @chaokunyang in #3692
- refactor(csharp): split Fory object attributes by @chaokunyang in #3709
- feat(c#): use sealed record for c# union by @chaokunyang in #3710
- feat(xlang): support unknown union case in union type by @chaokunyang in #3711
- refactor(compiler): rename generated schema owners to modules by @chaokunyang in #3713
Bug Fix
- fix(c++): propagate /Zc:preprocessor on MSVC for FORY_STRUCT consumers by @truffle-dev in #3694
- fix(cpp): repair CMake tests and examples by @chaokunyang in #3699
- fix(java): guard replace-resolve class reads by @chaokunyang in #3706
- fix(python): make policy validators validation-only by @chaokunyang in #3708
Other Improvements
- docs(cpp): clarify MSVC preprocessor requirement by @chaokunyang in #3695
- chore: bump release version to 1.0 by @chaokunyang in #3696
- chore(deps): bump io.grpc:grpc-netty-shaded from 1.62.2 to 1.75.0 in /integration_tests/grpc_tests/java by @dependabot[bot] in #3697
- docs(xlang): update language support docs by @chaokunyang in #3700
- docs: fix xlang type mapping MDX by @chaokunyang in #3701
- chore(js): upgrade test dependencies by @chaokunyang in #3703
- ci: declare workflow-level
contents: readon ci and lint by @arpitjain099 in #3704 - docs: update readme to add android support by @chaokunyang in #3705
- chore: update java checks docs by @chaokunyang in #3707
New Contributors
- @truffle-dev made their first contribution in #3694
- @arpitjain099 made their first contribution in #3704
Full Changelog: v1.0.0...v1.1.0-rc1
v1.0.0
The Apache Fory team is pleased to announce the 1.0.0 release. This milestone release includes 84 PRs from 11 distinct contributors and turns the cross-language runtime into the default path across supported languages. See the Install page to get the libraries for your platform.
Highlights
Apache Fory 1.0.0 standardizes the cross-language serialization model. The unified xlang type system is now the default mode across languages, with compatible-mode reads, simplified field ordering, and better list/array compatibility. The release also adds decimal and bfloat16 support for xlang serialization.
The language runtimes continue to converge around the same schema and metadata model. Nested container and field codec support landed across Rust, C++, C#, Go, Dart, Python, and Swift. Kotlin gains xlang, KSP, and schema IDL support, while Scala adds schema IDL support and updated generated annotations.
This release also expands deployment coverage and performance work. Java gains Android serialization support, annotation processor support and nested type-use serialization metadata. Dart typed-container fast paths and generated struct optimizations improve throughput, alongside refreshed benchmark plots.
Key Features:
- Unified xlang type system and default xlang mode: #3644, #3685
- Decimal and bfloat16 support for xlang serialization: #3599, #3605
- Nested container and field codec support: #3625, #3630, #3636, #3639, #3640, #3641, #3643
- Kotlin xlang, KSP, and schema IDL support: #3679, #3684
- Scala schema IDL support and generated annotation updates: #3681, #3682
- Android serialization and Java annotation processor support: #3667, #3670
- Xlang compatible-mode improvements: #3648, #3650, #3675
- Serialization performance improvements: #3609, #3653, #3656, #3661
- Java row accessors and nested type-use metadata: #3631, #3633
Features
- feat(ci): fix release for csharp and dart by @chaokunyang in #3582
- feat(rust): add configurable size guardrails by @ayush00git in #3579
- refactor(rust): move Fory configuration to builder by @chaokunyang in #3593
- feat(xlang): add decimal and align serializers for xlang by @chaokunyang in #3599
- refactor(dart): aligned dart internal implementation by @Geethapranay1 in #3601
- feat(xlang): add bfloat16 support by @chaokunyang in #3605
- feat(dart): support dart web platform by @chaokunyang in #3608
- perf(dart): typed-container write fast path with scan elimination by @yash-agarwa-l in #3609
- feat(swift): nested container override support for swift by @chaokunyang in #3625
- feat(java): add schema typed row fields accessor by @chaokunyang in #3631
- feat: add nested container codec for rust by @chaokunyang in #3630
- feat(java): support nested type-use serialization metadata by @chaokunyang in #3633
- refactor(cpp): remove abseil dependency by @chaokunyang in #3634
- feat(cpp): add nested field codec support by @chaokunyang in #3636
- feat(csharp): support nested container field codec by @chaokunyang in #3639
- feat(go): support nested field annotation type specs by @chaokunyang in #3640
- feat(dart): support nested container field codec for dart by @chaokunyang in #3641
- feat(python): support nested field schema encodings by @chaokunyang in #3643
- feat(xlang): unified xlang type system by @chaokunyang in #3644
- feat(xlang): add comprehensive read checks by @chaokunyang in #3647
- feat(xlang): use compatible for xlang by default by @chaokunyang in #3648
- feat(xlang): compatible read between list array field by @chaokunyang in #3650
- perf(dart): remove generated struct slot bridge by @chaokunyang in #3653
- perf: optimize serialization perf by @chaokunyang in #3656
- perf: update benchmark plots by @chaokunyang in #3661
- refactor(rust): use absolute path in generated Rust code by @BaldDemian in #3666
- feat: add android support by @chaokunyang in #3667
- feat(compiler): add helpers to generate unified gRPC service/method names by @BaldDemian in #3672
- feat(java): annotation processor for android serialization by @chaokunyang in #3670
- feat(xlang): simplify xlang field ordering by @chaokunyang in #3675
- feat(kotlin): add kotlin xlang and ksp support by @chaokunyang in #3679
- refactor(java): replace static serializer spi lookup by @chaokunyang in #3680
- feat(scala): add scala schema idl support by @chaokunyang in #3681
- feat(scala): update generated annotation by @chaokunyang in #3682
- feat(rust): make rust chrono optional by @chaokunyang in #3683
- feat(kotlin): add schema idl support to kotlin by @chaokunyang in #3684
- feat(xlang): use xlang as default mode for all languages by @chaokunyang in #3685
Bug Fixes
- fix(dart): resolve fory pub.dev score issues by @chaokunyang in #3585
- fix(dart): fix dart ci by @chaokunyang in #3586
- fix(dart): use getUint32 for correctly encoding u64 value by @ayush00git in #3592
- fix(c++): fix c++ duration serialization by @chaokunyang in #3598
- fix(javascript): align TypeMeta preamble constants with python/java/rust/go xlang bindings by @emrul in #3603
- fix(javascript): fix javascript schema idl tests by @chaokunyang in #3604
- fix(dart): added
>>>for correct logical right shift semantics in uint by @ayush00git in #3607 - fix(go): ensure physical buffer space for unsafe varint fast-paths by @ayush00git in #3613
- fix(go): add bound checking for refResolver and metaStringResolver reads by @ayush00git in #3615
- fix(go): added pre-allocation bounds checks for slices and strings by @ayush00git in #3618
- fix(go): added maxBinarySize limit to decimal deserialization by @ayush00git in #3623
- fix(go): add configurable fieldCount and fieldDepth guardrails by @ayush00git in #3620
- fix(java): honor record field encoding in generated decode by @mandrean in #3626
- fix(java): preserve externalizable containers in compatible mode by @mandrean in #3628
- fix(python): enforce more checks in read by @chaokunyang in #3632
- fix(xlang): fix xlang type system by @chaokunyang in #3646
- fix(java): use REPLACE_STUB_ID for unregistered writeReplace classes to prevent cross-JVM ClassNotFoundException by @wakilurislam in #3638
- fix(java): fix set view ref tracking by @chaokunyang in #3649
- fix(java): recover map declared serializers for compatible reads by @mandrean in #3654
- fix: include TypeMeta header bits in hash by @chaokunyang in #3659
- fix(java): serialize suppressed exceptions by @chaokunyang in #3663
- fix(javascript): preserve getTypeInfo in regenerated read serializer by @xhzq233 in #3669
- fix(java): validate subclass serializer layer counts by @chaokunyang in #3676
- fix(java): avoid instantiating abstract meta-share types by @chaokunyang in #3677
- fix: fix release script by @chaokunyang in #3687...
v1.0.0-rc1
Highlights
- Unified the xlang type system and made xlang the default mode across languages: #3644, #3685
- Added decimal and bfloat16 support for xlang serialization: #3599, #3605
- Added nested container and field codec support across Rust, C++, C#, Go, Dart, Python, and Swift: #3625, #3630, #3636, #3639, #3640, #3641, #3643
- Added Kotlin xlang, KSP, and schema IDL support: #3679, #3684
- Added Scala schema IDL support and updated generated annotations: #3681, #3682
- Added Android serialization support, including Java annotation processor support: #3667, #3670
- Improved xlang compatibility with default compatible mode, simplified field ordering, and list/array compatible reads: #3648, #3650, #3675
- Improved serialization performance, including Dart typed-container fast paths and generated struct optimizations: #3609, #3653, #3656, #3661
- Added Java schema typed row field accessors and nested type-use serialization metadata: #3631, #3633
Features
- feat(ci): fix release for csharp and dart by @chaokunyang in #3582
- feat(rust): add configurable size guardrails by @ayush00git in #3579
- refactor(rust): move Fory configuration to builder by @chaokunyang in #3593
- feat(xlang): add decimal and align serializers for xlang by @chaokunyang in #3599
- refactor(dart): aligned dart internal implementation by @Geethapranay1 in #3601
- feat(xlang): add bfloat16 support by @chaokunyang in #3605
- feat(dart): support dart web platform by @chaokunyang in #3608
- perf(dart): typed-container write fast path with scan elimination by @yash-agarwa-l in #3609
- feat(swift): nested container override support for swift by @chaokunyang in #3625
- feat(java): add schema typed row fields accessor by @chaokunyang in #3631
- feat: add nested container codec for rust by @chaokunyang in #3630
- feat(java): support nested type-use serialization metadata by @chaokunyang in #3633
- refactor(cpp): remove abseil dependency by @chaokunyang in #3634
- feat(cpp): add nested field codec support by @chaokunyang in #3636
- feat(csharp): support nested container field codec by @chaokunyang in #3639
- feat(go): support nested field annotation type specs by @chaokunyang in #3640
- feat(dart): support nested container field codec for dart by @chaokunyang in #3641
- feat(python): support nested field schema encodings by @chaokunyang in #3643
- feat(xlang): unified xlang type system by @chaokunyang in #3644
- feat(xlang): add comprehensive read checks by @chaokunyang in #3647
- feat(xlang): use compatible for xlang by default by @chaokunyang in #3648
- feat(xlang): compatible read between list array field by @chaokunyang in #3650
- perf(dart): remove generated struct slot bridge by @chaokunyang in #3653
- perf: optimize serialization perf by @chaokunyang in #3656
- perf: update benchmark plots by @chaokunyang in #3661
- refactor(rust): use absolute path in generated Rust code by @BaldDemian in #3666
- feat: add android support by @chaokunyang in #3667
- feat(compiler): add helpers to generate unified gRPC service/method names by @BaldDemian in #3672
- feat(java): annotation processor for android serialization by @chaokunyang in #3670
- feat(xlang): simplify xlang field ordering by @chaokunyang in #3675
- feat(kotlin): add kotlin xlang and ksp support by @chaokunyang in #3679
- refactor(java): replace static serializer spi lookup by @chaokunyang in #3680
- feat(scala): add scala schema idl support by @chaokunyang in #3681
- feat(scala): update generated annotation by @chaokunyang in #3682
- feat(rust): make rust chrono optional by @chaokunyang in #3683
- feat(kotlin): add schema idl support to kotlin by @chaokunyang in #3684
- feat(xlang): use xlang as default mode for all languages by @chaokunyang in #3685
Bug Fix
- fix(dart): resolve fory pub.dev score issues by @chaokunyang in #3585
- fix(dart): fix dart ci by @chaokunyang in #3586
- fix(dart): use getUint32 for correctly encoding u64 value by @ayush00git in #3592
- fix(c++): fix c++ duration serialization by @chaokunyang in #3598
- fix(javascript): align TypeMeta preamble constants with python/java/rust/go xlang bindings by @emrul in #3603
- fix(javascript): fix javascript schema idl tests by @chaokunyang in #3604
- fix(dart): added <<< for correct logical right shift semantics in uint by @ayush00git in #3607
- fix(go): ensure physical buffer space for unsafe varint fast-paths by @ayush00git in #3613
- fix(go): add bound checking for refResolver and metaStringResolver reads by @ayush00git in #3615
- fix(go): added pre-allocation bounds checks for slices and strings by @ayush00git in #3618
- fix(go): added maxBinarySize limit to decimal deserialization by @ayush00git in #3623
- fix(go): add configurable fieldCount and fieldDepth guardrails by @ayush00git in #3620
- fix(java): honor record field encoding in generated decode by @mandrean in #3626
- fix(java): preserve externalizable containers in compatible mode by @mandrean in #3628
- fix(python): enforce more checks in read by @chaokunyang in #3632
- fix(xlang): fix xlang type system by @chaokunyang in #3646
- fix(java): use REPLACE_STUB_ID for unregistered writeReplace classes to prevent cross-JVM ClassNotFoundException by @wakilurislam in #3638
- fix(java): fix set view ref tracking by @chaokunyang in #3649
- fix(java): recover map declared serializers for compatible reads by @mandrean in #3654
- fix: include TypeMeta header bits in hash by @chaokunyang in #3659
- fix(java): serialize suppressed exceptions by @chaokunyang in #3663
- fix(javascript): preserve getTypeInfo in regenerated read serializer by @xhzq233 in #3669
- fix(java): validate subclass serializer layer counts by @chaokunyang in #3676
- fix(java): avoid instantiating abstract meta-share types by @chaokunyang in #3677
- fix: fix release script by @chaokunyang in #3687
Other Improvements
- chore: bump releasse version to 0.17.0 by @chaokunyang in #3583
- chore: skip auto release for tag starts with go by @chaokunyang in #3584
- docs: add NuGet badge by @chaokunyang in #3587
- docs(java): update graalvm guide location by @chaokunyang in #3588
- docs: rename graalvm_support.md to graalvm-support.md by @chaokunyang in #3589
- chore(rust): refine varint read/write method name by @chaokunyang in #3590
- docs: move development guide to docs root by @chaokunyang in #3591
- chore(dart): add missing license headers by @chaokunyang in #3594
- chore(csharp): add more csharp and swift tests by @chaokunyang in #3597
- chore(dart): refine dart xlang serializati...
v0.17.0
The Apache Fory team is pleased to announce the 0.17.0 release. This is a major release that includes 71 PR from 19 distinct contributors. See the Install Page to learn how to get the libraries for your platform.
JavaScript/NodeJS Serialization: First Release
Apache Fory 0.17.0 marks the first release with official JavaScript/NodeJS
documentation, benchmark coverage, and TypeScript-friendly IDL code generation.
The JavaScript runtime is built for modern Node.js services and TypeScript
codebases, while preserving Fory's cross-language object model, schema-driven
APIs, and optional reference tracking.
Key capabilities:
- High-performance serialization for JavaScript and TypeScript objects in Node.js
- Cross-language compatibility with Java, Python, Go, Rust, C#, Swift, and Dart
- Schema-driven APIs via
Type.*builders and TypeScript decorators - Optional reference tracking for shared and circular object graphs
- Compatible mode for schema evolution
- Configurable depth, binary size, and collection size guardrails
- JavaScript/TypeScript target support in the Fory IDL/compiler workflow
- Optional
@apache-fory/hpsfast string path for Node.js 20+
Quick Start
import Fory, { Type } from "@apache-fory/core";
const userType = Type.struct(
{ typeName: "example.user" },
{
id: Type.int64(),
name: Type.string(),
age: Type.int32(),
},
);
const fory = new Fory();
const { serialize, deserialize } = fory.register(userType);
const bytes = serialize({
id: 1n,
name: "Alice",
age: 30,
});
const user = deserialize(bytes);
console.log(user);- JavaScript guide: https://fory.apache.org/docs/guide/javascript/
- Compiler docs: https://fory.apache.org/docs/compiler/
JavaScript Benchmarks
Below are throughput results (ops/sec; higher is better) comparing Fory with
Protocol Buffers and JSON across representative data structures.
| Datatype | Operation | Fory TPS | Protobuf TPS | JSON TPS | Fastest |
|---|---|---|---|---|---|
| Struct | Serialize | 8,453,950 | 1,903,706 | 3,058,232 | fory |
| Struct | Deserialize | 9,705,287 | 8,233,664 | 3,860,538 | fory |
| Sample | Serialize | 1,498,391 | 422,620 | 744,790 | fory |
| Sample | Deserialize | 1,918,162 | 819,010 | 762,048 | fory |
| MediaContent | Serialize | 1,293,157 | 729,497 | 1,299,908 | json |
| MediaContent | Deserialize | 1,638,086 | 1,209,140 | 921,191 | fory |
| StructList | Serialize | 3,928,325 | 495,648 | 891,810 | fory |
| StructList | Deserialize | 3,264,827 | 1,529,744 | 986,144 | fory |
| SampleList | Serialize | 355,581 | 92,741 | 163,120 | fory |
| SampleList | Deserialize | 424,916 | 163,253 | 162,520 | fory |
| MediaContentList | Serialize | 286,053 | 148,977 | 282,445 | fory |
| MediaContentList | Deserialize | 376,826 | 244,622 | 190,155 | fory |
Serialized data sizes (bytes):
| Datatype | Fory | Protobuf | JSON |
|---|---|---|---|
| Struct | 58 | 61 | 103 |
| Sample | 446 | 377 | 724 |
| MediaContent | 391 | 307 | 596 |
| StructList | 184 | 315 | 537 |
| SampleList | 1980 | 1900 | 3642 |
| MediaContentList | 1665 | 1550 | 3009 |
Benchmark details: https://github.com/apache/fory/tree/v0.17.0/benchmarks/javascript
Dart Serialization: First Release
Apache Fory 0.17.0 also marks the first release with official Dart
documentation, benchmark coverage, a rebuilt runtime, and Dart IDL support.
The Dart implementation focuses on generated serializers, stable
cross-language type identity, schema evolution, and predictable APIs for
service workloads.
Key capabilities:
- High-performance Dart serialization with generated code instead of reflection
- Cross-language compatibility with Java, Python, Go, Rust, C#, Swift, and JavaScript
@ForyStructand@ForyFieldannotations withbuild_runnercode generation- Compatible mode for schema evolution across versions
- Optional reference tracking for shared and circular object graphs
- Manual
Serializer<T>extension points for advanced or custom types - Dart target support in the Fory IDL/compiler workflow
Quick Start
import 'package:fory/fory.dart';
part 'person.fory.dart';
enum Color {
red,
blue,
}
@ForyStruct()
class Person {
Person();
String name = '';
Int32 age = Int32(0);
Color favoriteColor = Color.red;
}
void main() {
final fory = Fory();
PersonFory.register(
fory,
Color,
namespace: 'example',
typeName: 'Color',
);
PersonFory.register(
fory,
Person,
namespace: 'example',
typeName: 'Person',
);
final bytes = fory.serialize(Person()
..name = 'Ada'
..age = Int32(36)
..favoriteColor = Color.blue);
final roundTrip = fory.deserialize<Person>(bytes);
print(roundTrip.name);
}- Dart guide: https://fory.apache.org/docs/guide/dart/
- Compiler docs: https://fory.apache.org/docs/compiler/
Dart Benchmarks
Below are throughput results (ops/sec; higher is better) comparing Fory with
Protocol Buffers across representative data structures.
| Datatype | Operation | Fory TPS | Protobuf TPS | Fastest |
|---|---|---|---|---|
| Struct | Serialize | 3,989,432 | 1,884,653 | fory (2.12x) |
| Struct | Deserialize | 5,828,197 | 4,199,680 | fory (1.39x) |
| Sample | Serialize | 1,649,722 | 500,167 | fory (3.30x) |
| Sample | Deserialize | 2,060,113 | 785,109 | fory (2.62x) |
| MediaContent | Serialize | 800,876 | 391,235 | fory (2.05x) |
| MediaContent | Deserialize | 1,315,115 | 683,533 | fory (1.92x) |
| StructList | Serialize | 1,456,396 | 367,506 | fory (3.96x) |
| StructList | Deserialize | 1,921,006 | 645,958 | fory (2.97x) |
| SampleList | Serialize | 411,144 | 48,508 | fory (8.48x) |
| SampleList | Deserialize | 464,273 | 103,558 | fory (4.48x) |
| MediaContentList | Serialize | 186,870 | 77,029 | fory (2.43x) |
| MediaContentList | Deserialize | 330,293 | 128,215 | fory (2.58x) |
Serialized data sizes (bytes):
| Datatype | Fory | Protobuf |
|---|---|---|
| Struct | 58 | 61 |
| Sample | 446 | 377 |
| MediaContent | 365 | 307 |
| StructList | 184 | 315 |
| SampleList | 1980 | 1900 |
| MediaContentList | 1535 | 1550 |
Benchmark details: https://github.com/apache/fory/tree/v0.17.0/benchmarks/dart
Highlights
- refactor(java): refactor fory java serialization api by @chaokunyang in #3537
- refactor(python): refactor python serialization api by @chaokunyang in #3543
- feat(java): reduce java serializer memory usage by share across Fory instances by @chaokunyang in #3546
- feat(java): remove guava dependency from fory java by @chaokunyang in #3557
- refactor(dart): new dart implementation by @chaokunyang in #3551
Features
- refactor(javascript): rename apache-fory/fory to apache-fory/core by @chaokunyang in #3489
- feat(ci): add bazel downloads retry by @BaldDemian in #3492
- feat(go): add configurable size guardrails by @ayush00git in #3475
- refactor(ci): install Bazel using setup-bazel by @BaldDemian in #3494
- perf(rust): Rewrite Rust benchmarks around shared bench.proto data by @chaokunyang in #3497
- feat(cpp): add float16 to c++ by @UninspiredCarrot in #3487
- feat(java): add float support by @mengnankkkk in #3254
- feat(java): support java virtual threads by @chaokunyang in #3522
- perf(java): optimize thread safe fory for java by @chaokunyang in #3529
- test(cpp): optimize float16 sign symmetry test for ASAN by @Geethapranay1 in #3531
- feat(java): add dedicated exception serializers by @chaokunyang in #3536
- refactor(java): refactor fory java serialization api by @chaokunyang in #3537
- refactor(python): refactor python serialization api by @chaokunyang in #3543
- feat(dart): Introduce id based enum serialization by @yash-agarwa-l in #3482
- feat(javascript): add configurable size guardrails by @ayush00git in #3539
- feat(java): reduce java serializer memory usage by share across Fory instances by @chaokunyang in #3546
- refactor(javascript): move serialization runtime state into contexts by @chaokunyang in #3549
- refactor(swift): refine swift api by @chaokunyang i...
v0.17.0-rc2
Highlights
- refactor(java): refactor fory java serialization api by @chaokunyang in #3537
- refactor(python): refactor python serialization api by @chaokunyang in #3543
- feat(java): reduce java serializer memory usage by share across Fory instances by @chaokunyang in #3546
- feat(java): remove guava dependency from fory java by @chaokunyang in #3557
- refactor(dart): new dart implementation by @chaokunyang in #3551
Features
- refactor(javascript): rename apache-fory/fory to apache-fory/core by @chaokunyang in #3489
- feat(ci): add bazel downloads retry by @BaldDemian in #3492
- feat(go): add configurable size guardrails by @ayush00git in #3475
- refactor(ci): install Bazel using setup-bazel by @BaldDemian in #3494
- perf(rust): Rewrite Rust benchmarks around shared bench.proto data by @chaokunyang in #3497
- feat(cpp): add float16 to c++ by @UninspiredCarrot in #3487
- feat(java): add float support by @mengnankkkk in #3254
- feat(java): support java virtual threads by @chaokunyang in #3522
- perf(java): optimize thread safe fory for java by @chaokunyang in #3529
- test(cpp): optimize float16 sign symmetry test for ASAN by @Geethapranay1 in #3531
- feat(java): add dedicated exception serializers by @chaokunyang in #3536
- refactor(java): refactor fory java serialization api by @chaokunyang in #3537
- refactor(python): refactor python serialization api by @chaokunyang in #3543
- feat(dart): Introduce id based enum serialization by @yash-agarwa-l in #3482
- feat(javascript): add configurable size guardrails by @ayush00git in #3539
- feat(java): reduce java serializer memory usage by share across Fory instances by @chaokunyang in #3546
- refactor(javascript): move serialization runtime state into contexts by @chaokunyang in #3549
- refactor(swift): refine swift api by @chaokunyang in #3554
- feat(xlang): refine xlang api and enum serialization by @chaokunyang in #3555
- feat(java): remove guava dependency from fory java by @chaokunyang in #3557
- refactor(dart): new dart implementation by @chaokunyang in #3551
- feat(compiler): Add JavaScript/TypeScript IDL code generation by @miantalha45 in #3394
- perf(javascript): add javascript benchmark by @chaokunyang in #3562
- perf(dart): optimize struct deserialize with direct dispatch codegen by @yash-agarwa-l in #3563
- feat(dart): add dart IDL support by @chaokunyang in #3571
- feat(python): fix python struct xlang ref track error by @chaokunyang in #3574
- feat: make generate enum use id for wire format by @chaokunyang in #3576
Bug Fix
- fix(java): Restore compact codec fixed width optimizations by @stevenschlansker in #3478
- fix(rust): handle panics from fuzz-found edge cases by @utafrali in #3481
- fix(rust): add error handling logic for std duration; add support for chrono duration by @BaldDemian in #3490
- fix(compiler): validate rpc request/response types by @retryoos in #3493
- fix(c++): fix misaligned address access errors detected by UBSan in buffer.h by @BaldDemian in #3479
- fix(java): finalize codegen config hash on first use by @chaokunyang in #3495
- fix(rust): fix several panics detected by cargo-fuzz by @BaldDemian in #3483
- fix(java): handle private final map codegen by @chaokunyang in #3504
- fix(compiler): repair broken service example and add regression coverage by @VikingDeng in #3505
- fix(rust): deep clone TypeMeta to prevent UB in concurrent scenarios by @BaldDemian in #3511
- fix(compiler): fix failed tests in compiler; add compiler CI by @BaldDemian in #3516
- fix(compiler): allow qualified nested types in FDL rpc signatures by @VikingDeng in #3518
- fix(java): preserve ConcurrentSkipListSet comparator on copy by @mandrean in #3520
- test(compiler): add IR validation and codegen tests for gRPC service support by @darius024 in #3528
- fix(java): Correct resolution of dependent/nested serializers in GraalVM by @rakow in #3532
- fix(java): fix objectstream serializer async jit and graalvm support by @chaokunyang in #3534
- ci: fix Bazel cache paths for C++ workflows by @chaokunyang in #3535
- fix(python): fix wrong calling orders in visit_other by @BaldDemian in #3542
- fix(js): corrected the float64 array size by @ayush00git in #3541
- fix(java): configure type checker during build by @chaokunyang in #3550
- fix(java): auto-select child serializers for sorted containers by @chaokunyang in #3552
- fix(java): support skip optional sql serializers for java11+ by @chaokunyang in #3553
- fix(rust): apply consistent pascalcase naming for nested types by @utafrali in #3548
- fix(javascript): fix flaky javascript idl tests by @chaokunyang in #3565
- fix(swift): fix swift generated code compile warnings by @chaokunyang in #3566
- fix(java): add test for previous uncaught regression. by @PiotrDuz in #3573
Other Improvements
- chore(java): Update Spotless and Checkstyle to allow building with JDK25 by @stevenschlansker in #3476
- chore(java): Clean up Javadoc warnings, and fail the build if any new ones are introduced by @stevenschlansker in #3477
- chore: bump version to 0.16.0 by @chaokunyang in #3488
- docs: add python benchmark result to readme by @chaokunyang in #3496
- docs: fix benchmark plots by @chaokunyang in #3498
- docs: add fory code review skill by @chaokunyang in #3500
- chore: adjust skills softlinks by @chaokunyang in #3501
- chore(cpp): configure CI to extract and execute C++ code from Markdo… by @Tyooughtul in #3381
- docs: improve comments in Java generator by @codewithtarun2005 in #3507
- docs: refactor agents.md to reduce token usage by @chaokunyang in #3538
- docs: add ai-review policy by @chaokunyang in #3545
- chore: Bump org.apache.logging.log4j:log4j-core from 2.25.3 to 2.25.4 in /java/fory-test-core by @dependabot[bot] in #3556
- chore(javascript): rename ref tracking to ref by @chaokunyang in #3559
- docs(dart): add dart docs by @chaokunyang in #3560
- docs(javascript): add javascript docs by @chaokunyang in #3561
- docs: refine dart and javascript docs by @chaokunyang in #3567
- docs(dart): update dart benchmark docs by @yash-agarwa-l in #3568
- docs: update readme by @chaokunyang in #3575
New Contributors
- @utafrali made their first contribution in #3481
- @BaldDemian made their first contribution in #3490
- @retryoos made their first contribution in #3493
- @Tyooughtul made their first contribution in #3381
- @UninspiredCarrot made their first contribution in #3487
- @VikingDeng made their first contribution in #3505
- @codewithtarun2005 made their first contribution in #3507
- @darius024 made their first contribution in #3528
- @rakow made their first contribution in #3532
- @PiotrDuz made their first contribution in #3573
Full Changelog: v0.16.0...v0.17.0-rc2

