Skip to content

v1.6.0

Latest

Choose a tag to compare

@chaokunyang chaokunyang released this 07 Aug 06:50

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 --grpc

The 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

Bug Fix

Other Improvements

Full Changelog: v1.5.0...v1.6.0