| title | Code Generation |
|---|---|
| sidebar_position | 11 |
| id | codegen |
| license | Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. |
:::warning Experimental Feature Code generation is an experimental feature in Fory Go. The API and behavior may change in future releases. The standard runtime path remains the stable, recommended approach for most use cases. :::
Fory Go provides optional ahead-of-time (AOT) code generation for performance-critical paths. This generates dedicated serializers ahead of time and adds compile-time shape checks.
| Aspect | Standard Path | Code Generation |
|---|---|---|
| Setup | Zero configuration | Requires go generate |
| Performance | Excellent | Better on hot paths |
| Type Safety | Runtime validation | Compile-time checks |
| Maintenance | Automatic | Requires regeneration |
Use code generation when:
- Maximum performance is required
- Compile-time type safety is important
- Hot paths are performance-critical
Use the standard path when:
- Simple setup is preferred
- Types change frequently
- Dynamic typing is needed
- Code generation complexity is undesirable
Install the fory generator binary:
go install github.com/apache/fory/go/fory/cmd/fory@latest
GO111MODULE=on go get -u github.com/apache/fory/go/fory/cmd/foryEnsure $GOBIN or $GOPATH/bin is in your PATH.
Add the //fory:generate comment above structs:
package models
//fory:generate
type User struct {
ID int64 `json:"id"`
Name string `json:"name"`
}
//fory:generate
type Order struct {
ID int64
Customer string
Total float64
}Add a go:generate directive (once per file or package):
//go:generate fory -file models.goOr for the entire package:
//go:generate fory -pkg .go generate ./...This creates models_fory_gen.go with generated serializers.
The generator creates:
A compile-time check to detect struct changes:
// 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
var _ = func(x User) { _ = _User_expected(x) }Strongly-typed serialization methods:
type User_ForyGenSerializer struct{}
func NewSerializerFor_User() fory.Serializer {
return &User_ForyGenSerializer{}
}
func (User_ForyGenSerializer) WriteTyped(ctx *fory.WriteContext, v *User) error {
buf := ctx.Buffer()
buf.WriteInt64(v.ID)
ctx.WriteString(v.Name)
return nil
}
func (User_ForyGenSerializer) ReadTyped(ctx *fory.ReadContext, v *User) error {
err := ctx.Err()
buf := ctx.Buffer()
v.ID = buf.ReadInt64(err)
v.Name = ctx.ReadString()
if ctx.HasError() {
return ctx.TakeError()
}
return nil
}Serializers are registered in init():
func init() {
fory.RegisterSerializerFactory((*User)(nil), NewSerializerFor_User)
}Generate for a specific file:
fory -file models.goGenerate for a package:
fory -pkg ./modelsSpecify types explicitly:
fory -pkg ./models -type "User,Order"Force regeneration even if up-to-date:
fory --force -file models.goRegenerate when any of these change:
- Field additions, removals, or renames
- Field type changes
- Struct tag changes
- New structs with
//fory:generate
Fory includes a compile-time guard:
// If struct changed, this fails to compile
var _ = func(x User) { _ = _User_expected(x) }If you forget to regenerate, the build fails with a clear message.
When invoked via go generate, the generator detects stale code and retries:
- Detects compile error from guard
- Removes stale generated file
- Regenerates fresh code
Code generation supports:
- All primitive types (
bool,int*,uint*,float*,string) - Slices of primitives and structs
- Maps with supported key/value types
- Nested structs (must also be generated)
- Pointers to structs
All nested structs must also have //fory:generate:
//fory:generate
type Address struct {
City string
Country string
}
//fory:generate
type Person struct {
Name string
Address Address // Address must also be generated
}Recommended for libraries:
go generate ./...
git add *_fory_gen.go
git commit -m "Regenerate Fory serializers"Pros: Consumers can build without generator; reproducible builds Cons: Larger diffs; must remember to regenerate
Recommended for applications:
steps:
- run: go install github.com/apache/fory/go/fory/cmd/fory@latest
- run: go generate ./...
- run: go build ./...Generated code integrates transparently:
f := fory.New(fory.WithXlang(true))
// Fory automatically uses generated serializer if available
user := &User{ID: 1, Name: "Alice"}
data, _ := f.Serialize(user)
var result User
f.Deserialize(data, &result)No code changes needed - registration happens in init().
You can mix approaches:
//fory:generate
type HotPathStruct struct {
// Performance-critical, use codegen
}
type ColdPathStruct struct {
// Not annotated, uses the standard runtime serializer
}- API may change
- Not all edge cases tested
- May have undiscovered bugs
- Interface fields (dynamic types)
- Recursive types without pointers
- Private (unexported) fields
- Custom serializers
If generated serializers are unavailable, Fory falls back to the standard serializer path:
// If User_ForyGenSerializer is not linked in, Fory uses the standard path
f.Serialize(&User{})Ensure the binary is in PATH:
export PATH=$PATH:$(go env GOPATH)/binRegenerate:
go generate ./...Or force:
fory --force -file yourfile.goThe compile-time guard catches this:
cannot use x (variable of type User) as type _User_expected in argument
Run go generate to fix.
myproject/
├── models/
│ ├── models.go # Struct definitions
│ ├── models_fory_gen.go # Generated code
│ └── generate.go # go:generate directive
├── main.go
└── go.mod
models/generate.go:
package models
//go:generate fory -pkg .models/models.go:
package models
//fory:generate
type User struct {
ID int64
Name string
}No. The standard serializer path works without code generation.
Yes. Generated code is plain Go with no version-specific features.
Yes. Fory automatically uses generated serializers when available.
Run go generate ./... after struct changes.
For libraries: yes. For applications: either works.