Releases: apache/fory
Release list
v1.6.0
Highlights
- Enhanced Fory JSON with date/time format annotation, GraalVM code generation, and better performance.
- Added C++ gRPC code generation support.
- Aligned and enhanced Rust Row Format support.
Enhanced Fory JSON
Fory 1.6.0 expands Fory JSON's mapping and deployment capabilities while further optimizing its serialization and deserialization paths. The new JsonFormat annotation applies a DateTimeFormatter pattern in both directions and can select a time zone for instant-bearing values. It works on direct date/time fields and one direct wrapper level, including collection elements, optional values, and map values.
import java.time.Instant;
import java.time.LocalDate;
import java.util.List;
import org.apache.fory.json.ForyJson;
import org.apache.fory.json.annotation.JsonFormat;
public final class Schedule {
@JsonFormat(pattern = "dd/MM/uuuu")
public LocalDate day;
@JsonFormat(pattern = "dd/MM/uuuu")
public List<LocalDate> days;
@JsonFormat(pattern = "uuuu-MM-dd HH:mm:ss XXX", timezone = "Asia/Shanghai")
public Instant timestamp;
}
ForyJson json = ForyJson.builder().build();
Schedule schedule = json.fromJson(
"{\"day\":\"02/01/2024\",\"days\":[\"03/01/2024\"],"
+ "\"timestamp\":\"2024-01-02 11:04:05 +08:00\"}",
Schedule.class);
String encoded = json.toJson(schedule);Fory JSON now also supports generated codecs in GraalVM Native Image. Annotate reachable models with JsonType; to generate codecs for a particular completed configuration during image construction, expose it from a reachable ForyJsonProvider. Configurations not returned by a provider continue to use prepared interpreted codecs without requiring application reflection configuration.
import org.apache.fory.json.ForyJson;
import org.apache.fory.json.annotation.ForyJsonProvider;
import org.apache.fory.json.annotation.JsonType;
@JsonType
public final class User {
public long id;
public String name;
}
@ForyJsonProvider
public final class JsonConfigs {
public JsonConfigs() {}
public ForyJson api() {
return ForyJson.builder().writeNullFields(true).build();
}
}The optimized serialization and deserialization paths reduce overhead in common JSON workloads. See the Fory JSON annotations and GraalVM Native Image guides for the complete behavior and constraints.
C++ gRPC Code Generation
Fory Compiler can now generate synchronous C++ gRPC service companions from Fory IDL, protobuf IDL, or FlatBuffers IDL. gRPC C++ provides the transport while generated Fory codecs serialize request and response payloads, so service implementations do not perform manual serialization or type registration.
Define a service in Fory IDL and pass --grpc together with the C++ output option:
package demo.greeter;
message HelloRequest {
string name = 1;
}
message HelloReply {
string reply = 1;
}
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}foryc service.fdl --cpp_out=./generated/cpp --grpcThe compiler emits the C++ models, service interface, generated Fory codec, client stub, server adapter, and route implementations. Applications implement the generated interface and register its adapter with a normal gRPC C++ server:
#include "demo_greeter.service.grpc.h"
class MyGreeter final : public demo::greeter::service::Greeter {
public:
::grpc::Status SayHello(
::grpc::ServerContext* context,
const ::demo::greeter::HelloRequest* request,
::demo::greeter::HelloReply* response) override {
(void)context;
response->set_reply("Hello, " + request->name());
return ::grpc::Status::OK;
}
};
MyGreeter implementation;
demo::greeter::service::grpc::GreeterServiceGrpc service(&implementation);
::grpc::ServerBuilder builder;
builder.AddListeningPort("0.0.0.0:50051", ::grpc::InsecureServerCredentials());
builder.RegisterService(&service);
std::unique_ptr<::grpc::Server> server = builder.BuildAndStart();Unary, client-streaming, server-streaming, and bidirectional-streaming RPCs are supported through synchronous gRPC C++ APIs. See the C++ gRPC guide for dependencies, generated files, client usage, and build integration.
Aligned and Enhanced Rust Row Format
Rust Row Format now follows the Standard Row Format shared by Java, C++, and Python. It supports schema-driven structs, arrays, maps, nested rows, nullability, temporal values, and checked borrowed views. Readers can access selected fields and collection elements directly from encoded bytes without reconstructing the complete value.
use fory::{from_row, to_row, Error, ForyRow, RowView};
use std::collections::BTreeMap;
#[derive(ForyRow)]
struct UserProfile {
id: i64,
name: String,
scores: Vec<i32>,
labels: BTreeMap<String, String>,
}
fn main() -> Result<(), Error> {
let bytes = to_row(&UserProfile {
id: 42,
name: "Ada".to_owned(),
scores: vec![98, 100],
labels: BTreeMap::from([("team".to_owned(), "compiler".to_owned())]),
})?;
let row = from_row::<UserProfile>(&bytes)?;
assert_eq!(row.id()?, 42);
assert_eq!(row.name()?, "Ada");
assert_eq!(row.scores()?.get(1)?, 100);
assert_eq!(row.labels()?.value(0)?, "compiler");
assert_eq!(row.as_bytes(), bytes);
Ok(())
}Generated field methods, array iteration, and map indexed access return Result and validate the referenced bytes as they are accessed. to_row_into can reuse a caller-owned buffer for repeated encoding. See the Rust Row Format guide for the supported type matrix, binary layout, and cross-language schema requirements.
Features
- feat(java): use fixed Fory JSON execution states by @chaokunyang in #3897
- feat: add more read checks by @chaokunyang in #3898
- feat(compiler): support C++ gRPC code generation by @BaldDemian in #3877
- feat(java): add JSON date/time format annotation by @chaokunyang in #3908
- feat: bound unbacked container deserialization by @chaokunyang in #3910
- feat(json): add GraalVM codegen support for json by @chaokunyang in #3907
- feat(java): support timezone in JSON date formats by @chaokunyang in #3911
- refactor: unify read progress capability naming by @chaokunyang in #3912
- feat(java): add JSON graph budgets and validators by @chaokunyang in #3909
- feat(rust): align row format with specification by @chaokunyang in #3913
- feat(rust): enhance rust row format by @chaokunyang in #3915
- perf(json): optimize json performance by @chaokunyang in #3914
Bug Fix
- fix(ci): pin Ruff version to 0.15.22 by @BaldDemian in #3900
Other Improvements
- docs(java): publish JSON benchmark results by @chaokunyang in #3895
- docs: rename manual serializers to custom serializers by @chaokunyang in #3896
- chore(release): bump versions after 1.5.0 by @chaokunyang in #3905
- docs(java): document cyclic container limitation by @chaokunyang in #3906
- docs: reorganize documentation by capability by @chaokunyang in #3916
- docs: update start docs by @chaokunyang in #3918
- chore: Bump brace-expansion in /javascript by @dependabot[bot] in #3917
- docs(json): update docs by @chaokunyang in #3919
- chore: Bump brace-expansion, @typescript-eslint/eslint-plugin, @typescript-eslint/parser, eslint, jest and ts-jest in /javascript by @dependabot[bot] in #3920
Full Changelog: v1.5.0...v1.6.0
v1.6.0-rc1
Highlights
- Enhanced Fory JSON with date/time format annotation, GraalVM code generation, and better performance.
- Added C++ gRPC code generation support.
- Aligned and enhanced Rust Row Format support.
Features
- feat(java): use fixed Fory JSON execution states by @chaokunyang in #3897
- feat: add more read checks by @chaokunyang in #3898
- feat(compiler): support C++ gRPC code generation by @BaldDemian in #3877
- feat(java): add JSON date/time format annotation by @chaokunyang in #3908
- feat: bound unbacked container deserialization by @chaokunyang in #3910
- feat(json): add GraalVM codegen support for json by @chaokunyang in #3907
- feat(java): support timezone in JSON date formats by @chaokunyang in #3911
- refactor: unify read progress capability naming by @chaokunyang in #3912
- feat(java): add JSON graph budgets and validators by @chaokunyang in #3909
- feat(rust): align row format with specification by @chaokunyang in #3913
- feat(rust): enhance rust row format by @chaokunyang in #3915
- perf(json): optimize json performance by @chaokunyang in #3914
Bug Fix
- fix(ci): pin Ruff version to 0.15.22 by @BaldDemian in #3900
Other Improvements
- docs(java): publish JSON benchmark results by @chaokunyang in #3895
- docs: rename manual serializers to custom serializers by @chaokunyang in #3896
- chore(release): bump versions after 1.5.0 by @chaokunyang in #3905
- docs(java): document cyclic container limitation by @chaokunyang in #3906
- docs: reorganize documentation by capability by @chaokunyang in #3916
- docs: update start docs by @chaokunyang in #3918
- chore: Bump brace-expansion in /javascript by @dependabot[bot] in #3917
- docs(json): update docs by @chaokunyang in #3919
- chore: Bump brace-expansion, @typescript-eslint/eslint-plugin, @typescript-eslint/parser, eslint, jest and ts-jest in /javascript by @dependabot[bot] in #3920
Full Changelog: v1.5.0...v1.6.0-rc1
v1.5.0
The Apache Fory team is pleased to announce the 1.5.0 release. This release includes 25 PRs. See the Install page to get the libraries for your platform.
Highlights
- Fory JSON is now up to 5× faster than Jackson and 10× faster than Gson.
- External-type serialization now covers Rust, Dart, Swift, and C#, allowing generated serializers for third-party structural types.
- C# and Dart now support class inheritance, with Dart also supporting intentional omission of inherited private fields.
Faster Fory JSON
Fory 1.5.0 delivers a major performance leap for Fory JSON, with deep optimizations across both serialization and deserialization. It is now up to 5× faster than Jackson and 10× faster than Gson.
| Representation | Operation | fory-json ops/sec | Jackson ops/sec | Gson ops/sec | vs. Jackson | vs. Gson |
|---|---|---|---|---|---|---|
| String | Serialize | 7,387,465 | 2,049,368 | 1,084,042 | 3.60× | 6.81× |
| String | Deserialize | 2,897,955 | 1,074,885 | 902,772 | 2.70× | 3.21× |
| UTF-8 bytes | Serialize | 10,375,498 | 1,868,614 | 1,037,211 | 5.55× | 10.00× |
| UTF-8 bytes | Deserialize | 3,077,158 | 1,268,397 | 933,079 | 2.43× | 3.30× |
External-Type Serialization For Rust/Swift/CSharp/Dart
Fory 1.5.0 adds external-type serialization to Rust, Dart, Swift, and C#. Applications can define a local serializer or schema declaration for a third-party structural type that cannot be modified to carry Fory annotations. Fory then reads and writes the target value directly—without requiring a wrapper or intermediate mirror object.
The generated declaration preserves the runtime's normal registration and wire model. In xlang mode, external structs, enums, and unions use the same applicable identities and encodings as directly supported types. Private, opaque, or invariant-bearing targets can still use a custom serializer when structural generation is not appropriate.
In Rust, the local derive names the target type and is selected explicitly for root values:
use fory::{Fory, ForyStruct};
#[derive(ForyStruct)]
#[fory(target = third_party::User)]
struct UserSerializer {
name: String,
age: u32,
}
let mut fory = Fory::builder().xlang(true).build();
fory.register::<UserSerializer>(100)?;
let bytes = fory.serialize_with::<UserSerializer>(&user)?;
let decoded =
fory.deserialize_with::<UserSerializer>(&bytes)?;Dart generates a serializer from a local target declaration, then registers the third-party target through the generated module:
@ForyStruct(target: third_party.User)
abstract final class UserSerializer {
@ForyField(id: 1)
late final String name;
@ForyField(id: 2, type: Int32Type())
late final int age;
}
ExternalSerializersForyModule.register(
fory,
third_party.User,
id: 100,
);Swift registers and selects the external serializer while the application continues to pass ThirdParty.User values:
@ForyStruct(target: ThirdParty.User.self)
struct UserSerializer {
var name: String
var age: UInt32
}
try fory.register(UserSerializer.self, id: 100)
let bytes = try fory.serialize(user, with: UserSerializer.self)
let decoded = try fory.deserialize(bytes, with: UserSerializer.self)C# source generation uses a local abstract declaration and registers the target type through the normal API:
using Apache.Fory;
using S = Apache.Fory.Schema.Types;
[ForyStruct(Target = typeof(ThirdParty.User))]
internal abstract class UserSerializer
{
[ForyField(1)]
public abstract string Name { get; }
[ForyField(2, Type = typeof(S.Int32))]
public abstract int Age { get; }
}
fory.Register<ThirdParty.User>(100);
byte[] bytes = fory.Serialize(user);For construction requirements, nested containers, dynamic values, and advanced mappings, see the dedicated guides for Rust, Dart, Swift, and C#.
Class Inheritance for C# and Dart
Fory 1.5.0 adds class inheritance support to C# and Dart. In both runtimes, inherited and child storage is represented as one flattened schema rather than a nested base object, so ordinary field ordering, schema evolution, reference tracking, and graph-memory checks continue to apply to the concrete type.
In C#, annotate every participating class directly because [ForyStruct] is not inherited. Abstract annotated bases provide schema fields for their concrete descendants, while only the concrete derived type is registered:
[ForyStruct]
public abstract class Entity
{
[ForyField(1)]
private long _id;
public long Id => _id;
}
[ForyStruct]
public sealed class User : Entity
{
[ForyField(2)]
public string Name { get; set; } = string.Empty;
}
fory.Register<User>(102);Dart generation discovers superclass and applied-mixin storage. Public inherited fields need no annotation on the parent, and a concrete child can intentionally omit inherited private fields:
class MessageBase {
int sequence = 0;
String _cache = '';
}
@ForyStruct(ignoreInheritedPrivateFields: true)
class TextMessage extends MessageBase {
TextMessage();
String text = '';
}The generated TextMessage schema contains sequence and text, but not the inherited private _cache. The option does not omit inherited public fields or private fields declared by the child itself.
See C# class inheritance and Dart inheritance for constructor rules, private-field access across packages, mixins, generics, references, and schema compatibility.
Features
- feat(java): add configurable JSON benchmark reports by @chaokunyang in #3870
- feat(java): optimize json perf by @chaokunyang in #3871
- feat(rust): support external-type serialization by @chaokunyang in #3881
- feat(dart): add external-type serialization by @chaokunyang in #3886
- feat(swift): support external-type serialization by @chaokunyang in #3888
- feat(csharp): support external type serialization by @chaokunyang in #3889
- feat(xlang): harden external type support by @chaokunyang in #3890
- feat(csharp): support generated class inheritance by @chaokunyang in #3893
- feat(dart): add dart inheriance support by @chaokunyang in #3892
- feat(dart): allow omitting inherited private fields by @chaokunyang in #3894
Bug Fix
- fix(cpp): validate tagged struct field reads by @chaokunyang in #3884
- fix(xlang): reject malformed meta strings by @chaokunyang in #3885
- fix(cpp): validate polymorphic smart pointer reads by @chaokunyang in #3887
- fix: fix release errors by @chaokunyang in #3891
Other Improvements
- chore: fix release script by @chaokunyang in #3867
- chore: Bump protobufjs from 7.6.2 to 7.6.3 in /javascript by @dependabot[bot] in #3868
- chore: Bump com.fasterxml.jackson.core:jackson-databind from 2.22.0 to 2.22.1 in /benchmarks/java by @dependabot[bot] in #3869
- docs: add java json serialization doc by @chaokunyang in #3875
- chore: fix package metadata links by @chaokunyang in #3876
- chore: Bump protobufjs from 7.6.3 to 7.6.5 in /javascript by @dependabot[bot] in #3878
- chore: Bump tar from 7.5.16 to 7.5.20 in /javascript by @dependabot[bot] in #3879
- chore: Bump com.fasterxml.jackson.core:jackson-core from 2.18.6 to 2.18.8 in /java/fory-testsuite by @dependabot[bot] in #3880
- chore: Bump tar from 7.5.20 to 7.5.22 in /javascript by @dependabot[bot] in #3882
- chore(deps): upgrade test deps by @chaokunyang in #3883
Full Changelog: v1.4.0...v1.5.0
v1.5.0-rc2
Highlights
- Added external-type serialization across Rust, Dart, Swift, and C#, with hardened cross-language interoperability.
- Added generated class inheritance support for C# and Dart.
- Improved Java JSON serialization performance and added configurable benchmark reports and documentation.
Features
- feat(java): add configurable JSON benchmark reports by @chaokunyang in #3870
- feat(java): optimize json perf by @chaokunyang in #3871
- feat(rust): support external-type serialization by @chaokunyang in #3881
- feat(dart): add external-type serialization by @chaokunyang in #3886
- feat(swift): support external-type serialization by @chaokunyang in #3888
- feat(csharp): support external type serialization by @chaokunyang in #3889
- feat(xlang): harden external type support by @chaokunyang in #3890
- feat(csharp): support generated class inheritance by @chaokunyang in #3893
- feat(dart): add dart inheriance support by @chaokunyang in #3892
- feat(dart): allow omitting inherited private fields by @chaokunyang in #3894
Bug Fix
- fix(cpp): validate tagged struct field reads by @chaokunyang in #3884
- fix(xlang): reject malformed meta strings by @chaokunyang in #3885
- fix(cpp): validate polymorphic smart pointer reads by @chaokunyang in #3887
- fix: fix release errors by @chaokunyang in #3891
Other Improvements
- chore: fix release script by @chaokunyang in #3867
- chore: Bump protobufjs from 7.6.2 to 7.6.3 in /javascript by @dependabot[bot] in #3868
- chore: Bump com.fasterxml.jackson.core:jackson-databind from 2.22.0 to 2.22.1 in /benchmarks/java by @dependabot[bot] in #3869
- docs: add java json serialization doc by @chaokunyang in #3875
- chore: fix package metadata links by @chaokunyang in #3876
- chore: Bump protobufjs from 7.6.3 to 7.6.5 in /javascript by @dependabot[bot] in #3878
- chore: Bump tar from 7.5.16 to 7.5.20 in /javascript by @dependabot[bot] in #3879
- chore: Bump com.fasterxml.jackson.core:jackson-core from 2.18.6 to 2.18.8 in /java/fory-testsuite by @dependabot[bot] in #3880
- chore: Bump tar from 7.5.20 to 7.5.22 in /javascript by @dependabot[bot] in #3882
- chore(deps): upgrade test deps by @chaokunyang in #3883
Full Changelog: v1.4.0...v1.5.0-rc1
v1.5.0-rc1
Highlights
- Added external-type serialization across Rust, Dart, Swift, and C#, with hardened cross-language interoperability.
- Added generated class inheritance support for C# and Dart.
- Improved Java JSON serialization performance and added configurable benchmark reports and documentation.
Features
- feat(java): add configurable JSON benchmark reports by @chaokunyang in #3870
- feat(java): optimize json perf by @chaokunyang in #3871
- feat(rust): support external-type serialization by @chaokunyang in #3881
- feat(dart): add external-type serialization by @chaokunyang in #3886
- feat(swift): support external-type serialization by @chaokunyang in #3888
- feat(csharp): support external type serialization by @chaokunyang in #3889
- feat(xlang): harden external type support by @chaokunyang in #3890
- feat(csharp): support generated class inheritance by @chaokunyang in #3893
- feat(dart): add dart inheriance support by @chaokunyang in #3892
Bug Fix
- fix(cpp): validate tagged struct field reads by @chaokunyang in #3884
- fix(xlang): reject malformed meta strings by @chaokunyang in #3885
- fix(cpp): validate polymorphic smart pointer reads by @chaokunyang in #3887
- fix: fix release errors by @chaokunyang in #3891
Other Improvements
- chore: fix release script by @chaokunyang in #3867
- chore: Bump protobufjs from 7.6.2 to 7.6.3 in /javascript by @dependabot[bot] in #3868
- chore: Bump com.fasterxml.jackson.core:jackson-databind from 2.22.0 to 2.22.1 in /benchmarks/java by @dependabot[bot] in #3869
- chore(release): bump versions for 1.4.0 by @chaokunyang in #3874
- docs: add java json serialization doc by @chaokunyang in #3875
- chore: fix package metadata links by @chaokunyang in #3876
- chore: Bump protobufjs from 7.6.3 to 7.6.5 in /javascript by @dependabot[bot] in #3878
- chore: Bump tar from 7.5.16 to 7.5.20 in /javascript by @dependabot[bot] in #3879
- chore: Bump com.fasterxml.jackson.core:jackson-core from 2.18.6 to 2.18.8 in /java/fory-testsuite by @dependabot[bot] in #3880
- chore: Bump tar from 7.5.20 to 7.5.22 in /javascript by @dependabot[bot] in #3882
- chore(deps): upgrade test deps by @chaokunyang in #3883
Full Changelog: v1.4.0...v1.5.0-rc1
v1.4.0
Highlights
- Introduced Fory JSON for Java, featuring high-performance code generation, rich annotations and mix-ins, dynamic properties, and support for Android and GraalVM native images.
- Improved performance, safety, and compatibility with a configurable container memory budget, more efficient stream deserialization, Python 3.14 support, and numerous cross-runtime fixes.
Fory JSON for Java
Fory 1.4.0 introduces Fory JSON, a high-performance, thread-safe JSON serialization framework for Java applications. It provides direct mapping between standard JSON and idiomatic Java domain objects, making it suitable for HTTP APIs, browser traffic, logs, configuration, and other interoperable text payloads.
Its main capabilities include:
- High-performance serialization: optimized readers and writers work with interpreted and runtime-generated serializers to accelerate both JSON encoding and decoding.
- Rich Java object mapping: ordinary classes, Java records, immutable creator-based classes, common JDK types, and generic containers are supported.
- Flexible customization: annotations, mix-ins, and custom codecs adapt application types to JSON, covering property names, order, inclusion, creators, polymorphism, unwrapped values, dynamic properties, and specialized representations.
- Broad platform support: supports JDK 8 and later, Android, and GraalVM native images.
Add the fory-json artifact to your application:
<dependency>
<groupId>org.apache.fory</groupId>
<artifactId>fory-json</artifactId>
<version>1.4.0</version>
</dependency>ForyJson is immutable and thread-safe after construction, so one instance can be reused across threads:
import org.apache.fory.json.ForyJson;
public final class JsonExample {
private static final ForyJson JSON = ForyJson.builder().build();
public static final class User {
public long id;
public String name;
public User() {}
}
public static void main(String[] args) {
User user = new User();
user.id = 7;
user.name = "Alice";
// Serialize to JSON text and deserialize from text.
String text = JSON.toJson(user);
User fromText = JSON.fromJson(text, User.class);
// Serialize directly to UTF-8 bytes and deserialize without an intermediate String.
byte[] utf8 = JSON.toJsonBytes(user);
User fromUtf8 = JSON.fromJson(utf8, User.class);
}
}See the Fory JSON documentation for the complete type model, annotations and mix-ins, dynamic properties, custom serializers, security controls, and Android or GraalVM setup.
Features
- feat(java): direct static varhandle field accessors by @chaokunyang in #3778
- feat(python): add Python 3.14 CI and wheels by @chaokunyang in #3781
- feat(java): add fory json serialization by @chaokunyang in #3784
- feat(java): optimize java serialization perf by @chaokunyang in #3794
- feat(format): support custom codecs keyed on Optional by @stevenschlansker in #3800
- feat(java): refine java json serde by @chaokunyang in #3806
- perf(java): avoid quadratic buffer growth in stream deserialization by @temni in #3809
- ci(swift): enforce swift-format by @chaokunyang in #3812
- ci: reuse cached Swift build artifacts by @chaokunyang in #3811
- refactor(go): remove static codegen by @chaokunyang in #3815
- feat: add container memory budget by @chaokunyang in #3795
- feat(java): add once logging APIs by @chaokunyang in #3821
- perf(java): optimize java json serde performace by @chaokunyang in #3808
- feat(java): add async codegen for Fory JSON by @chaokunyang in #3825
- feat(java): add json type checker by @chaokunyang in #3829
- feat(java): refactor json codec api by @chaokunyang in #3830
- perf(java): optimize json serialize perf by @chaokunyang in #3834
- feat(java): add fory json annotations by @chaokunyang in #3835
- feat(compiler): handle C++ identifier escaping and name collisions by @BaldDemian in #3839
- feat(java): enhance class check by @chaokunyang in #3837
- feat(java): add json property order annotation by @chaokunyang in #3840
- feat(json): support dynamic object properties by @chaokunyang in #3841
- refactor(java): simplify JSON subtype member writing by @chaokunyang in #3842
- feat(java): add JSON codec annotation by @chaokunyang in #3844
- refactor(java): embed GraalVM feature in core by @chaokunyang in #3845
- feat(java): support Fory JSON in GraalVM native image by @chaokunyang in #3846
- feat(java): make DefaultJdkClassAllowList public by @eryanwcp in #3849
- feat(java): update AllowListChecker to include checks against disallowed and allowed class lists by @eryanwcp in #3850
- feat(java): support Fory JSON on Android by @chaokunyang in #3852
- refactor(java): simplify json codec annotations by @chaokunyang in #3854
- feat(java): add json value annotations by @chaokunyang in #3855
- feat(java): generate JSON object/record codecs helper for android by @chaokunyang in #3857
- feat(java): support JSON unwrapped properties by @chaokunyang in #3856
- feat(java): add Json object field cache by @chaokunyang in #3862
- feat(java): add json mixin support by @chaokunyang in #3863
- feat(java): add abstract json value codec by @chaokunyang in #3865
- perf(java): fix json perf regression by @chaokunyang in #3866
Bug Fix
- fix(java): log ForyBuilder advisories at info level by @chaokunyang in #3777
- fix(java): fix unbounded LinkedBlockingQueue deserialization by @00sense in #3786
- fix(ci): checkstyle CI error output by @stevenschlansker in #3796
- fix(c++): replace deprecated std::aligned_storage by @RisinT96 in #3793
- fix(c++): make temporal types hashable by @BaldDemian in #3789
- fix(java): add JDK25 trusted lookup Unsafe fallback by @chaokunyang in #3802
- fix(compiler): reject any, message and union as map key types by @BaldDemian in #3804
- fix(java): fix collection get element type bug by @Pigsy-Monk in #3803
- fix(compiler): reject optional any in IDL validation by @BaldDemian in #3807
- fix(compiler): never generate C++ equality methods for message and union containing any by @BaldDemian in #3810
- fix(Java): prevent StackOverflow in normalizeIterableTypeArguments for self-referential collections by @Pigsy-Monk in #3817
- fix(compiler): alias C++ union case types in metadata macros by @BaldDemian in #3814
- fix(compiler): use protobuf syntax highlighter in docs by @ayush00git in #3819
- fix(C++): add unordered_map type info hooks by @BaldDemian in #3820
- fix(rust): stabilize meta string dynamic cache by @chaokunyang in #3822
- fix: keep skip reference ids aligned by @chaokunyang in #3823
- fix(rust): fix mulmurhash compute by @chaokunyang in #3824
- fix(java): preserve collection TypeDef serializer family by @chaokunyang in #3827
- fix(java): stabilize readResolve type metadata by @chaokunyang in #3831
- fix(java): skip missing compatible struct fields by @chaokunyang in #3833
- fix(java): support inherited fields in xlang by @chaokunyang in #3838
- fix(java): support guava android collections by @chaokunyang in #3851
- fix(java): stabilize GraalVM field offsets by @chaokunyang in #3853
- fix(java): restore inherited container field types by @chaokunyang in #3864
Other Improvements
- chore: fold Fory review skill into agent guidance by @chaokunyang in #3779
- chore(javascript): add javascript code format by @chaokunyang in #3813
- docs(compiler): documented grpc service stubs by @ayush00git in #3818
New Contributors
- @00sense made their first contribution in #3786
- @RisinT96 made their first contribution in https://gith...
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

