tree: 834926f9bef1c8a4e0ab6a00244f7a511027f6a8 [path history] [tgz]
  1. fory/
  2. README.md
go/README.md

Apache Fory™ Go

Fory is a blazingly fast multi-language serialization framework powered by just-in-time compilation and zero-copy.

Fory Go provides two serialization paths: a high-performance code generation path and a reflection-based path. The code generation path is recommended for production use as it offers better performance and broader type support.

Supported Types

Fory Go supports the following types for both reflection-based serialization and code generation:

Basic Data Types

  • bool
  • int8, int16, int32, int64, int
  • uint8 (byte)
  • float32, float64
  • string

Collection Types

  • []bool, []int16, []int32, []int64
  • []float32, []float64
  • []string
  • []interface{} (dynamic slice)
  • map[string]string, map[int]int, map[string]int

Fory Go Codegen (optional)

This repository includes an optional ahead-of-time (AOT) code generator for Fory. The runtime reflection-based path continues to work; codegen exists to provide additional performance, type safety and zero-reflection overhead for hot paths. You can adopt it incrementally, per package or per file.

Why codegen (rationale)

  • Faster (no reflection on the hot path)
  • Type-safe serialization/deserialization with predictable layouts
  • Smaller GC pressure and fewer allocations
  • Compile-time guards to detect stale generated code when struct definitions change

Note: Code generation is not mandatory. If you prefer simple workflows, you can keep using the reflection-based API.

Install the generator

The generator binary is fory.

  • Go 1.16+ (recommended):
go install github.com/apache/fory/go/fory/cmd/fory@latest
  • Go 1.13+:
# Inside a module-enabled environment
GO111MODULE=on go get -u github.com/apache/fory/go/fory/cmd/fory

# Or clone the repo and install from source
git clone https://github.com/apache/fory.git
cd fory/go/fory
go install ./cmd/fory

Ensure $GOBIN or $GOPATH/bin is on your PATH so that fory is discoverable by go generate.

Usage: annotate and generate

  1. Mark structs for generation with //fory:generate, and add a go:generate directive. File-based generation is recommended.
package yourpkg

//fory:generate
type User struct {
    ID   int64  `json:"id"`
    Name string `json:"name"`
}

//go:generate fory -file structs.go

Then run:

go generate

The generator will create structs_fory_gen.go next to your source file and register serializers in init().

  1. Explicit types (legacy mode) are also supported:
fory -pkg ./models -type "User,Order"

When to re-run go generate

Re-run generation whenever any of the following change for generated structs:

  • Field additions/removals/renames
  • Field type changes or tag changes
  • New structs annotated with //fory:generate

Fory adds a compile-time guard in generated files to detect stale code. If you forget to re-generate, your build will fail with a clear message. The generator also includes a smart auto-retry: when invoked via go generate, it detects this situation, removes the stale generated file, and retries automatically. You can force this behavior manually with:

fory --force -file structs.go

What gets generated (simplified example)

Below is a minimal illustration. Actual output includes strongly-typed serializers, interface-compatible methods, registration, and a compile-time snapshot of your struct.

// Code generated by fory. DO NOT EDIT.
package yourpkg

// Snapshot of User's underlying type at generation time.
type _User_expected struct {
    ID   int64
    Name string
}

// Compile-time check: fails if User no longer matches the snapshot.
// If this fails, run: go generate
var _ = func(x User) { _ = _User_expected(x) }

type User_ForyGenSerializer struct{}

func (User_ForyGenSerializer) WriteTyped(f *fory.Fory, buf *fory.ByteBuffer, v *User) error {
    // write fields in a stable order
    buf.WriteInt64(v.ID)
    fory.WriteString(buf, v.Name)
    return nil
}

func (User_ForyGenSerializer) ReadTyped(f *fory.Fory, buf *fory.ByteBuffer, v *User) error {
    v.ID = buf.ReadInt64()
    v.Name = fory.ReadString(buf)
    return nil
}

CI and version control (should I check in generated code?)

Both models are supported; choose based on your workflow:

  • Check in generated code (recommended for libraries)

    • Pros: Consumers can build without the generator; reproducible builds
    • Cons: Larger diffs; must remember to re-generate before commit
  • Do not check in; generate in CI/release pipeline (recommended for apps)

    • Add a step to your pipeline, e.g.:
      • go generate ./...
      • Optionally fory --force -file <file.go> for targeted regeneration

Regardless of your choice, the compile-time guard ensures that stale code is noticed early. If a build fails due to the guard in a local environment, run:

go generate
# If needed
fory --force -file <your file>

FAQ

  • Is codegen required? No. Fory works without it via reflection.
  • Does generated code work across Go versions? Yes, it’s plain Go code; keep your toolchain consistent in CI.
  • Can I mix generated and non-generated structs? Yes, adoption is incremental and per file.

Configuration Options

Fory Go supports several configuration options through the functional options pattern:

Compatible Mode (Meta share mode)

Compatible mode enables meta information sharing, which allows for schema evolution:

// Enable compatible mode with meta share
fory := NewForyWithOptions(WithCompatible(true))

Reference Tracking

Enable reference tracking:

fory := NewForyWithOptions(WithRefTracking(true))

Combined Options

You can combine multiple options:

fory := NewForyWithOptions(
    WithCompatible(true),
    WithRefTracking(true),
)

Best Practices

Type Registration Patterns

Choose the right registration approach for your use case:

// Register using an explicit namespace and type name pair.
func (f *Fory) RegisterByNamespace(User{}, "example", "user") error

// Register using a name
func (f *Fory) RegisterNamedType(User{}, "example.user") error

// Register using a pre-assigned numeric type identifier.
func (f *Fory) Register(User{}, 101) error

How to test

cd go/fory
go test -v ./...
go test -v fory_xlang_test.go

Code Style

cd go/fory
gofmt -s -w .

When using Go's gofmt -s -w . command on Windows, ensure your source files use Unix-style line endings (LF) instead of Windows-style (CRLF). Go tools expect LF by default, and mismatched line endings may cause unexpected behavior or unnecessary changes in version control.

Before committing, you can use git config core.autocrlf input to take effect on future commits.