title: Generated Code sidebar_position: 5 id: generated_code 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
This document explains the code generated by the FDL compiler for each target language.
The examples in this document use this FDL schema:
package demo; enum Status [id=100] { PENDING = 0; ACTIVE = 1; COMPLETED = 2; } message User [id=101] { string id = 1; string name = 2; optional string email = 3; int32 age = 4; } message Order [id=102] { string id = 1; ref User customer = 2; repeated string items = 3; map<string, int32> quantities = 4; Status status = 5; }
When enum values use a protobuf-style prefix (enum name in UPPER_SNAKE_CASE), the compiler automatically strips the prefix for languages with scoped enums. This produces cleaner, more idiomatic code.
Input FDL:
enum DeviceTier { DEVICE_TIER_UNKNOWN = 0; DEVICE_TIER_TIER1 = 1; DEVICE_TIER_TIER2 = 2; }
Generated output by language:
| Language | Generated Values | Notes |
|---|---|---|
| Java | UNKNOWN, TIER1, TIER2 | Scoped enum |
| Rust | Unknown, Tier1, Tier2 | PascalCase variants |
| C++ | UNKNOWN, TIER1, TIER2 | Scoped enum class |
| Python | UNKNOWN, TIER1, TIER2 | Scoped IntEnum |
| Go | DeviceTierUnknown, DeviceTierTier1, ... | Unscoped, prefix re-added |
Note: Go uses unscoped constants, so the enum name prefix is added back to avoid naming collisions.
When using nested message and enum definitions, the generated code varies by language.
Input FDL:
message SearchResponse { message Result { string url = 1; string title = 2; } repeated Result results = 1; }
public class SearchResponse { public static class Result { private String url; private String title; // getters, setters... } private List<Result> results; // getters, setters... }
@dataclass class SearchResponse: @dataclass class Result: url: str = "" title: str = "" results: List[Result] = field(default_factory=list)
type SearchResponse_Result struct {
Url string
Title string
}
type SearchResponse struct {
Results []SearchResponse_Result
}
Note: Set option (fory).go_nested_type_style = "camelcase"; to generate SearchResponseResult instead.
pub mod search_response { use super::*; #[derive(ForyObject)] pub struct Result { pub url: String, pub title: String, } } #[derive(ForyObject)] pub struct SearchResponse { pub results: Vec<search_response::Result>, }
class SearchResponse final { public: class Result final { public: std::string url; std::string title; }; std::vector<Result> results; }; FORY_STRUCT(SearchResponse::Result, url, title); FORY_STRUCT(SearchResponse, results);
Summary:
| Language | Approach | Syntax Example |
|---|---|---|
| Java | Static inner classes | SearchResponse.Result |
| Python | Nested dataclasses | SearchResponse.Result |
| Go | Underscore (configurable) | SearchResponse_Result |
| Rust | Nested module | search_response::Result |
| C++ | Nested classes | SearchResponse::Result |
FDL unions generate type-safe APIs with an explicit active case. This example is based on integration_tests/idl_tests/idl/addressbook.fdl:
package addressbook; message Dog [id=104] { string name = 1; int32 bark_volume = 2; } message Cat [id=105] { string name = 1; int32 lives = 2; } union Animal [id=106] { Dog dog = 1; Cat cat = 2; } message Person [id=100] { Animal pet = 8; }
Animal pet = Animal.ofDog(new Dog()); if (pet.hasDog()) { Dog dog = pet.getDog(); } Animal.AnimalCase caseId = pet.getAnimalCase();
pet = Animal.dog(Dog(name="Rex", bark_volume=5)) if pet.is_dog(): dog = pet.dog_value() case_id = pet.case_id()
pet := DogAnimal(&Dog{Name: "Rex", BarkVolume: 5})
if dog, ok := pet.AsDog(); ok {
_ = dog
}
_ = pet.Visit(AnimalVisitor{
Dog: func(d *Dog) error { return nil },
})
let pet = Animal::Dog(Dog { name: "Rex".into(), bark_volume: 5, });
addressbook::Animal pet = addressbook::Animal::dog( addressbook::Dog{"Rex", 5}); if (pet.is_dog()) { const addressbook::Dog& dog = pet.dog(); }
Generated registration helpers also register union types, for example:
fory.registerUnion(Animal.class, 106, new UnionSerializer(...))fory.register_union(Animal, type_id=106, serializer=AnimalSerializer(fory))f.RegisterUnion(...)fory.register_union::<Animal>(106)?FORY_UNION(addressbook::Animal, ...)package demo; public enum Status { PENDING, ACTIVE, COMPLETED; }
package demo; import java.util.List; import java.util.Map; import org.apache.fory.annotation.ForyField; public class User { private String id; private String name; @ForyField(nullable = true) private String email; private int age; public User() { } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
package demo; import java.util.List; import java.util.Map; import org.apache.fory.annotation.ForyField; public class Order { private String id; @ForyField(ref = true) private User customer; private List<String> items; private Map<String, Integer> quantities; private Status status; public Order() { } // Getters and setters... }
package demo; import org.apache.fory.Fory; public class DemoForyRegistration { public static void register(Fory fory) { fory.register(Status.class, 100); fory.register(User.class, 101); fory.register(Order.class, 102); } }
import demo.*; import org.apache.fory.Fory; import org.apache.fory.config.Language; public class Example { public static void main(String[] args) { Fory fory = Fory.builder() .withLanguage(Language.XLANG) .withRefTracking(true) .build(); DemoForyRegistration.register(fory); User user = new User(); user.setId("u123"); user.setName("Alice"); user.setAge(30); Order order = new Order(); order.setId("o456"); order.setCustomer(user); order.setStatus(Status.ACTIVE); byte[] bytes = fory.serialize(order); Order restored = (Order) fory.deserialize(bytes); } }
# Licensed to the Apache Software Foundation (ASF)... from dataclasses import dataclass from enum import IntEnum from typing import Dict, List, Optional import pyfory class Status(IntEnum): PENDING = 0 ACTIVE = 1 COMPLETED = 2 @dataclass class User: id: str = "" name: str = "" email: Optional[str] = None age: pyfory.int32 = 0 @dataclass class Order: id: str = "" customer: Optional[User] = None items: List[str] = None quantities: Dict[str, pyfory.int32] = None status: Status = None def register_demo_types(fory: pyfory.Fory): fory.register_type(Status, type_id=100) fory.register_type(User, type_id=101) fory.register_type(Order, type_id=102)
import pyfory from demo import User, Order, Status, register_demo_types fory = pyfory.Fory(ref_tracking=True) register_demo_types(fory) user = User(id="u123", name="Alice", age=30) order = Order( id="o456", customer=user, items=["item1", "item2"], quantities={"item1": 2, "item2": 1}, status=Status.ACTIVE ) data = fory.serialize(order) restored = fory.deserialize(data)
// Licensed to the Apache Software Foundation (ASF)... package demo import ( fory "github.com/apache/fory/go/fory" ) type Status int32 const ( StatusPending Status = 0 StatusActive Status = 1 StatusCompleted Status = 2 ) type User struct { Id string Name string Email *string `fory:"nullable"` Age int32 } type Order struct { Id string Customer *User `fory:"ref"` Items []string Quantities map[string]int32 Status Status } func RegisterTypes(f *fory.Fory) error { if err := f.RegisterEnum(Status(0), 100); err != nil { return err } if err := f.Register(User{}, 101); err != nil { return err } if err := f.Register(Order{}, 102); err != nil { return err } return nil }
package main import ( "demo" fory "github.com/apache/fory/go/fory" ) func main() { f := fory.NewFory(true) // Enable ref tracking if err := demo.RegisterTypes(f); err != nil { panic(err) } email := "alice@example.com" user := &demo.User{ Id: "u123", Name: "Alice", Email: &email, Age: 30, } order := &demo.Order{ Id: "o456", Customer: user, Items: []string{"item1", "item2"}, Quantities: map[string]int32{ "item1": 2, "item2": 1, }, Status: demo.StatusActive, } bytes, err := f.Marshal(order) if err != nil { panic(err) } var restored demo.Order if err := f.Unmarshal(bytes, &restored); err != nil { panic(err) } }
// Licensed to the Apache Software Foundation (ASF)... use fory::{Fory, ForyObject}; use std::collections::HashMap; use std::sync::Arc; #[derive(ForyObject, Debug, Clone, PartialEq, Default)] #[repr(i32)] pub enum Status { #[default] Pending = 0, Active = 1, Completed = 2, } #[derive(ForyObject, Debug, Clone, PartialEq, Default)] pub struct User { pub id: String, pub name: String, #[fory(nullable = true)] pub email: Option<String>, pub age: i32, } #[derive(ForyObject, Debug, Clone, PartialEq, Default)] pub struct Order { pub id: String, pub customer: Arc<User>, pub items: Vec<String>, pub quantities: HashMap<String, i32>, pub status: Status, } pub fn register_types(fory: &mut Fory) -> Result<(), fory::Error> { fory.register::<Status>(100)?; fory.register::<User>(101)?; fory.register::<Order>(102)?; Ok(()) }
Note: Rust uses Arc by default for ref fields. In FDL, use ref(thread_safe = false) to generate Rc, and ref(weak = true) to generate ArcWeak/RcWeak. For protobuf/IDL extensions, use [(fory).thread_safe_pointer = false] and [(fory).weak_ref = true].
use demo::{User, Order, Status, register_types}; use fory::Fory; use std::sync::Arc; use std::collections::HashMap; fn main() -> Result<(), fory::Error> { let mut fory = Fory::default(); register_types(&mut fory)?; let user = Arc::new(User { id: "u123".to_string(), name: "Alice".to_string(), email: Some("alice@example.com".to_string()), age: 30, }); let mut quantities = HashMap::new(); quantities.insert("item1".to_string(), 2); quantities.insert("item2".to_string(), 1); let order = Order { id: "o456".to_string(), customer: user, items: vec!["item1".to_string(), "item2".to_string()], quantities, status: Status::Active, }; let bytes = fory.serialize(&order)?; let restored: Order = fory.deserialize(&bytes)?; Ok(()) }
/* * Licensed to the Apache Software Foundation (ASF)... */ #ifndef DEMO_H_ #define DEMO_H_ #include <cstdint> #include <map> #include <memory> #include <optional> #include <string> #include <vector> #include "fory/serialization/fory.h" namespace demo { struct User; struct Order; enum class Status : int32_t { PENDING = 0, ACTIVE = 1, COMPLETED = 2, }; FORY_ENUM(Status, PENDING, ACTIVE, COMPLETED); struct User { std::string id; std::string name; std::optional<std::string> email; int32_t age; bool operator==(const User& other) const { return id == other.id && name == other.name && email == other.email && age == other.age; } }; FORY_STRUCT(User, id, name, email, age); struct Order { std::string id; std::shared_ptr<User> customer; std::vector<std::string> items; std::map<std::string, int32_t> quantities; Status status; bool operator==(const Order& other) const { return id == other.id && customer == other.customer && items == other.items && quantities == other.quantities && status == other.status; } }; FORY_STRUCT(Order, id, customer, items, quantities, status); inline void RegisterTypes(fory::serialization::Fory& fory) { fory.register_enum<Status>(100); fory.register_struct<User>(101); fory.register_struct<Order>(102); } } // namespace demo #endif // DEMO_H_
#include "demo.h" #include <iostream> int main() { fory::serialization::Fory fory = fory::serialization::Fory::builder() .xlang(true) .ref_tracking(true) .build(); demo::RegisterTypes(fory); auto user = std::make_shared<demo::User>(); user->id = "u123"; user->name = "Alice"; user->email = "alice@example.com"; user->age = 30; demo::Order order; order.id = "o456"; order.customer = user; order.items = {"item1", "item2"}; order.quantities = {{"item1", 2}, {"item2", 1}}; order.status = demo::Status::ACTIVE; auto bytes = fory.serialize(order); auto restored = fory.deserialize<demo::Order>(bytes); return 0; }
Note: C++ uses std::shared_ptr<T> for ref fields. Set ref(weak = true) in FDL (or [(fory).weak_ref = true] in protobuf) to generate fory::serialization::SharedWeak<T> for weak references.
| Annotation | Purpose |
|---|---|
@ForyField(nullable = true) | Marks field as nullable |
@ForyField(ref = true) | Enables reference tracking |
| Hint | Purpose |
|---|---|
Optional[T] | Nullable field |
List[T] | Repeated field |
Dict[K, V] | Map field |
pyfory.int32 | Fixed-width integer |
| Tag | Purpose |
|---|---|
fory:"nullable" | Marks field as nullable |
fory:"ref" | Enables reference tracking |
| Attribute | Purpose |
|---|---|
#[derive(ForyObject)] | Enables Fory serialization |
#[fory(nullable = true)] | Marks field as nullable |
#[repr(i32)] | Enum representation |
| Macro | Purpose |
|---|---|
FORY_STRUCT(T[, fields..]) | Registers struct fields |
FORY_ENUM(T, values..) | Registers enum values |
When types don't have explicit type IDs, they use namespace-based registration:
package myapp.models; message Config { // No @id string key = 1; string value = 2; }
Java:
fory.register(Config.class, "myapp.models", "Config");
Python:
fory.register_type(Config, namespace="myapp.models", typename="Config")
Go:
f.RegisterTagType("myapp.models.Config", Config{})
Rust:
fory.register_by_namespace::<Config>("myapp.models", "Config")?;
C++:
fory.register_struct<Config>("myapp.models", "Config");
Generated code can be extended through language-specific mechanisms:
Java: Use inheritance or composition:
public class ExtendedUser extends User { public String getDisplayName() { return getName() + " <" + getEmail() + ">"; } }
Python: Add methods after import:
from demo import User def get_display_name(self): return f"{self.name} <{self.email}>" User.get_display_name = get_display_name
Go: Use separate file in same package:
package demo
func (u *User) DisplayName() string {
return u.Name + " <" + *u.Email + ">"
}
Rust: Use trait extensions:
trait UserExt { fn display_name(&self) -> String; } impl UserExt for User { fn display_name(&self) -> String { format!("{} <{}>", self.name, self.email.as_deref().unwrap_or("")) } }
C++: Use inheritance or free functions:
std::string display_name(const demo::User& user) { return user.name + " <" + user.email.value_or("") + ">"; }