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

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.

This document explains the code generated by the FDL compiler for each target language.

Example Schema

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;
}

Enum Prefix Stripping

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:

LanguageGenerated ValuesNotes
JavaUNKNOWN, TIER1, TIER2Scoped enum
RustUnknown, Tier1, Tier2PascalCase variants
C++UNKNOWN, TIER1, TIER2Scoped enum class
PythonUNKNOWN, TIER1, TIER2Scoped IntEnum
GoDeviceTierUnknown, DeviceTierTier1, ...Unscoped, prefix re-added

Note: Go uses unscoped constants, so the enum name prefix is added back to avoid naming collisions.

Nested Types

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;
}

Java - Inner Classes

public class SearchResponse {
    public static class Result {
        private String url;
        private String title;
        // getters, setters...
    }

    private List<Result> results;
    // getters, setters...
}

Python - Nested Classes

@dataclass
class SearchResponse:
    @dataclass
    class Result:
        url: str = ""
        title: str = ""

    results: List[Result] = field(default_factory=list)

Go - Underscore

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.

Rust - Nested Module

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>,
}

C++ - Nested Classes

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:

LanguageApproachSyntax Example
JavaStatic inner classesSearchResponse.Result
PythonNested dataclassesSearchResponse.Result
GoUnderscore (configurable)SearchResponse_Result
RustNested modulesearch_response::Result
C++Nested classesSearchResponse::Result

Union Generation

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;
}

Java

Animal pet = Animal.ofDog(new Dog());
if (pet.hasDog()) {
    Dog dog = pet.getDog();
}
Animal.AnimalCase caseId = pet.getAnimalCase();

Python

pet = Animal.dog(Dog(name="Rex", bark_volume=5))
if pet.is_dog():
    dog = pet.dog_value()
case_id = pet.case_id()

Go

pet := DogAnimal(&Dog{Name: "Rex", BarkVolume: 5})
if dog, ok := pet.AsDog(); ok {
    _ = dog
}
_ = pet.Visit(AnimalVisitor{
    Dog: func(d *Dog) error { return nil },
})

Rust

let pet = Animal::Dog(Dog {
    name: "Rex".into(),
    bark_volume: 5,
});

C++

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:

  • Java: fory.registerUnion(Animal.class, 106, new UnionSerializer(...))
  • Python: fory.register_union(Animal, type_id=106, serializer=AnimalSerializer(fory))
  • Go: f.RegisterUnion(...)
  • Rust: fory.register_union::<Animal>(106)?
  • C++: FORY_UNION(addressbook::Animal, ...)

Java

Enum Generation

package demo;

public enum Status {
    PENDING,
    ACTIVE,
    COMPLETED;
}

Message Generation

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...
}

Registration Helper

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);
    }
}

Usage

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);
    }
}

Python

Module Generation

# 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)

Usage

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)

Go

File Generation

// 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
}

Usage

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)
    }
}

Rust

Module Generation

// 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].

Usage

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(())
}

C++

Header Generation

/*
 * 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_

Usage

#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.

Generated Annotations Summary

Java Annotations

AnnotationPurpose
@ForyField(nullable = true)Marks field as nullable
@ForyField(ref = true)Enables reference tracking

Python Type Hints

HintPurpose
Optional[T]Nullable field
List[T]Repeated field
Dict[K, V]Map field
pyfory.int32Fixed-width integer

Go Struct Tags

TagPurpose
fory:"nullable"Marks field as nullable
fory:"ref"Enables reference tracking

Rust Attributes

AttributePurpose
#[derive(ForyObject)]Enables Fory serialization
#[fory(nullable = true)]Marks field as nullable
#[repr(i32)]Enum representation

C++ Macros

MacroPurpose
FORY_STRUCT(T[, fields..])Registers struct fields
FORY_ENUM(T, values..)Registers enum values

Name-Based Registration

When types don't have explicit type IDs, they use namespace-based registration:

FDL

package myapp.models;

message Config {  // No @id
    string key = 1;
    string value = 2;
}

Generated Registration

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");

Customization

Extending Generated Code

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("") + ">";
}