title: Cross-Language Serialization sidebar_position: 80 id: cross_language 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
Fory Go enables seamless data exchange with Java, Python, C++, Rust, and JavaScript. This guide covers cross-language compatibility and type mapping.
Cross-language (xlang) mode must be explicitly enabled:
f := fory.New(fory.WithXlang(true))
Use consistent type IDs across all languages:
type User struct {
ID int64
Name string
}
f := fory.New(fory.WithXlang(true))
f.RegisterStruct(User{}, 1)
data, _ := f.Serialize(&User{ID: 1, Name: "Alice"})
public class User { public long id; public String name; } Fory fory = Fory.builder().withXlang(true).build(); fory.register(User.class, 1); User user = fory.deserialize(data, User.class);
from dataclasses import dataclass import pyfory @dataclass class User: id: pyfory.Int64Type name: str fory = pyfory.Fory(xlang=True) fory.register(User, type_id=1) user = fory.deserialize(data)
See Type Mapping Specification for detailed type mappings across all languages.
Cross-language serialization requires consistent field ordering. Fory sorts fields by their snake_case names alphabetically.
Go field names are converted to snake_case for sorting:
type Example struct { UserID int64 // -> user_id FirstName string // -> first_name Age int32 // -> age } // Sorted order: age, first_name, user_id
Ensure other languages use matching field names that produce the same snake_case ordering, or use field IDs for explicit control:
type Example struct {
UserID int64 `fory:"id=0"`
FirstName string `fory:"id=1"`
Age int32 `fory:"id=2"`
}
Go (Serializer):
type Order struct { ID int64 Customer string Total float64 Items []string } f := fory.New(fory.WithXlang(true)) f.RegisterStruct(Order{}, 1) order := &Order{ ID: 12345, Customer: "Alice", Total: 99.99, Items: []string{"Widget", "Gadget"}, } data, _ := f.Serialize(order) // Send 'data' to Java service
Java (Deserializer):
public class Order { public long id; public String customer; public double total; public List<String> items; } Fory fory = Fory.builder().withXlang(true).build(); fory.register(Order.class, 1); Order order = fory.deserialize(data, Order.class);
Python (Serializer):
from dataclasses import dataclass import pyfory @dataclass class Message: id: pyfory.Int64Type content: str timestamp: pyfory.Int64Type fory = pyfory.Fory(xlang=True) fory.register(Message, type_id=1) msg = Message(id=1, content="Hello from Python", timestamp=1234567890) data = fory.serialize(msg)
Go (Deserializer):
type Message struct { ID int64 Content string Timestamp int64 } f := fory.New(fory.WithXlang(true)) f.RegisterStruct(Message{}, 1) var msg Message f.Deserialize(data, &msg) fmt.Println(msg.Content) // "Hello from Python"
Cross-language nested structures require all types to be registered:
Go:
type Address struct {
Street string
City string
Country string
}
type Company struct {
Name string
Address Address
}
f := fory.New(fory.WithXlang(true))
f.RegisterStruct(Address{}, 1)
f.RegisterStruct(Company{}, 2)
Java:
public class Address { public String street; public String city; public String country; } public class Company { public String name; public Address address; } fory.register(Address.class, 1); fory.register(Company.class, 2);
Go uses PascalCase, other languages may use camelCase or snake_case. Fields are matched by their snake_case conversion:
// Go type User struct { FirstName string // -> first_name } // Java - field name converted to snake_case must match public class User { public String firstName; // -> first_name (matches) }
Go unsigned types map to Java signed types with the same bit pattern:
var value uint64 = 18446744073709551615 // Max uint64
Java's long holds the same bits but interprets as -1. Use Long.toUnsignedString() in Java if unsigned interpretation is needed.
Go nil slices/maps serialize differently based on configuration:
var slice []string = nil // In xlang mode: serializes based on nullable configuration
Ensure other languages handle null appropriately.