Common types can be serialized automatically: primitive numeric types, string, binary, array, list, map and so on.
Java
import org.apache.fury.*; import org.apache.fury.config.*; import java.util.*; public class Example1 { public static void main(String[] args) { Fury fury = Fury.builder().withLanguage(Language.XLANG).build(); List<Object> list = ofArrayList(true, false, "str", -1.1, 1, new int[100], new double[20]); byte[] bytes = fury.serialize(list); // bytes can be data serialized by other languages. fury.deserialize(bytes); Map<Object, Object> map = new HashMap<>(); map.put("k1", "v1"); map.put("k2", list); map.put("k3", -1); bytes = fury.serialize(map); // bytes can be data serialized by other languages. fury.deserialize(bytes); } }
Python
import pyfury import numpy as np fury = pyfury.Fury() object_list = [True, False, "str", -1.1, 1, np.full(100, 0, dtype=np.int32), np.full(20, 0.0, dtype=np.double)] data = fury.serialize(object_list) # bytes can be data serialized by other languages. new_list = fury.deserialize(data) object_map = {"k1": "v1", "k2": object_list, "k3": -1} data = fury.serialize(object_map) # bytes can be data serialized by other languages. new_map = fury.deserialize(data) print(new_map)
Golang
package main import furygo "github.com/apache/incubator-fury/fury/go/fury" import "fmt" func main() { list := []interface{}{true, false, "str", -1.1, 1, make([]int32, 10), make([]float64, 20)} fury := furygo.NewFury() bytes, err := fury.Marshal(list) if err != nil { panic(err) } var newValue interface{} // bytes can be data serialized by other languages. if err := fury.Unmarshal(bytes, &newValue); err != nil { panic(err) } fmt.Println(newValue) dict := map[string]interface{}{ "k1": "v1", "k2": list, "k3": -1, } bytes, err = fury.Marshal(dict) if err != nil { panic(err) } // bytes can be data serialized by other languages. if err := fury.Unmarshal(bytes, &newValue); err != nil { panic(err) } fmt.Println(newValue) }
JavaScript
import Fury from '@furyjs/fury'; /** * @furyjs/hps use v8's fast-calls-api that can be called directly by jit, ensure that the version of Node is 20 or above. * Experimental feature, installation success cannot be guaranteed at this moment * If you are unable to install the module, replace it with `const hps = null;` **/ import hps from '@furyjs/hps'; const fury = new Fury({ hps }); const input = fury.serialize('hello fury'); const result = fury.deserialize(input); console.log(result);
Rust
use chrono::{NaiveDate, NaiveDateTime}; use fury::{from_buffer, to_buffer, Fury}; use std::collections::HashMap; fn run() { let bin: Vec<u8> = to_buffer(&"hello".to_string()); let obj: String = from_buffer(&bin).expect("should success"); assert_eq!("hello".to_string(), obj); }
Serializing user-defined types needs registering the custom type using the register API to establish the mapping relationship between the type in different languages.
Java
import org.apache.fury.*; import org.apache.fury.config.*; import java.util.*; public class Example2 { public static class SomeClass1 { Object f1; Map<Byte, Integer> f2; } public static class SomeClass2 { Object f1; String f2; List<Object> f3; Map<Byte, Integer> f4; Byte f5; Short f6; Integer f7; Long f8; Float f9; Double f10; short[] f11; List<Short> f12; } public static Object createObject() { SomeClass1 obj1 = new SomeClass1(); obj1.f1 = true; obj1.f2 = ofHashMap((byte) -1, 2); SomeClass2 obj = new SomeClass2(); obj.f1 = obj1; obj.f2 = "abc"; obj.f3 = ofArrayList("abc", "abc"); obj.f4 = ofHashMap((byte) 1, 2); obj.f5 = Byte.MAX_VALUE; obj.f6 = Short.MAX_VALUE; obj.f7 = Integer.MAX_VALUE; obj.f8 = Long.MAX_VALUE; obj.f9 = 1.0f / 2; obj.f10 = 1 / 3.0; obj.f11 = new short[]{(short) 1, (short) 2}; obj.f12 = ofArrayList((short) -1, (short) 4); return obj; } // mvn exec:java -Dexec.mainClass="org.apache.fury.examples.Example2" public static void main(String[] args) { Fury fury = Fury.builder().withLanguage(Language.XLANG).build(); fury.register(SomeClass1.class, "example.SomeClass1"); fury.register(SomeClass2.class, "example.SomeClass2"); byte[] bytes = fury.serialize(createObject()); // bytes can be data serialized by other languages. System.out.println(fury.deserialize(bytes)); } }
Python
from dataclasses import dataclass from typing import List, Dict, Any import pyfury, array @dataclass class SomeClass1: f1: Any f2: Dict[pyfury.Int8Type, pyfury.Int32Type] @dataclass class SomeClass2: f1: Any = None f2: str = None f3: List[str] = None f4: Dict[pyfury.Int8Type, pyfury.Int32Type] = None f5: pyfury.Int8Type = None f6: pyfury.Int16Type = None f7: pyfury.Int32Type = None # int type will be taken as `pyfury.Int64Type`. # use `pyfury.Int32Type` for type hint if peer # are more narrow type. f8: int = None f9: pyfury.Float32Type = None # float type will be taken as `pyfury.Float64Type` f10: float = None f11: pyfury.Int16ArrayType = None f12: List[pyfury.Int16Type] = None if __name__ == "__main__": f = pyfury.Fury() f.register_class(SomeClass1, type_tag="example.SomeClass1") f.register_class(SomeClass2, type_tag="example.SomeClass2") obj1 = SomeClass1(f1=True, f2={-1: 2}) obj = SomeClass2( f1=obj1, f2="abc", f3=["abc", "abc"], f4={1: 2}, f5=2 ** 7 - 1, f6=2 ** 15 - 1, f7=2 ** 31 - 1, f8=2 ** 63 - 1, f9=1.0 / 2, f10=1 / 3.0, f11=array.array("h", [1, 2]), f12=[-1, 4], ) data = f.serialize(obj) # bytes can be data serialized by other languages. print(f.deserialize(data))
Golang
package main import furygo "github.com/apache/incubator-fury/fury/go/fury" import "fmt" func main() { type SomeClass1 struct { F1 interface{} F2 string F3 []interface{} F4 map[int8]int32 F5 int8 F6 int16 F7 int32 F8 int64 F9 float32 F10 float64 F11 []int16 F12 fury.Int16Slice } type SomeClas2 struct { F1 interface{} F2 map[int8]int32 } fury := furygo.NewFury() if err := fury.RegisterTagType("example.SomeClass1", SomeClass1{}); err != nil { panic(err) } if err := fury.RegisterTagType("example.SomeClass2", SomeClass2{}); err != nil { panic(err) } obj1 := &SomeClass1{} obj1.F1 = true obj1.F2 = map[int8]int32{-1: 2} obj := &SomeClass1{} obj.F1 = obj1 obj.F2 = "abc" obj.F3 = []interface{}{"abc", "abc"} f4 := map[int8]int32{1: 2} obj.F4 = f4 obj.F5 = fury.MaxInt8 obj.F6 = fury.MaxInt16 obj.F7 = fury.MaxInt32 obj.F8 = fury.MaxInt64 obj.F9 = 1.0 / 2 obj.F10 = 1 / 3.0 obj.F11 = []int16{1, 2} obj.F12 = []int16{-1, 4} bytes, err := fury.Marshal(obj); if err != nil { panic(err) } var newValue interface{} // bytes can be data serialized by other languages. if err := fury.Unmarshal(bytes, &newValue); err != nil { panic(err) } fmt.Println(newValue) }
JavaScript
import Fury, { Type, InternalSerializerType } from '@furyjs/fury'; /** * @furyjs/hps use v8's fast-calls-api that can be called directly by jit, ensure that the version of Node is 20 or above. * Experimental feature, installation success cannot be guaranteed at this moment * If you are unable to install the module, replace it with `const hps = null;` **/ import hps from '@furyjs/hps'; // Now we describe data structures using JSON, but in the future, we will use more ways. const description = Type.object('example.foo', { foo: Type.string(), }); const fury = new Fury({ hps }); const { serialize, deserialize } = fury.registerSerializer(description); const input = serialize({ foo: 'hello fury' }); const result = deserialize(input); console.log(result);
Rust
use chrono::{NaiveDate, NaiveDateTime}; use fury::{from_buffer, to_buffer, Fury}; use std::collections::HashMap; #[test] fn complex_struct() { #[derive(Fury, Debug, PartialEq)] #[tag("example.foo2")] struct Animal { category: String, } #[derive(Fury, Debug, PartialEq)] #[tag("example.foo")] struct Person { c1: Vec<u8>, // binary c2: Vec<i16>, // primitive array animal: Vec<Animal>, c3: Vec<Vec<u8>>, name: String, c4: HashMap<String, String>, age: u16, op: Option<String>, op2: Option<String>, date: NaiveDate, time: NaiveDateTime, c5: f32, c6: f64, } let person: Person = Person { c1: vec![1, 2, 3], c2: vec![5, 6, 7], c3: vec![vec![1, 2], vec![1, 3]], animal: vec![Animal { category: "Dog".to_string(), }], c4: HashMap::from([ ("hello1".to_string(), "hello2".to_string()), ("hello2".to_string(), "hello3".to_string()), ]), age: 12, name: "helo".to_string(), op: Some("option".to_string()), op2: None, date: NaiveDate::from_ymd_opt(2025, 12, 12).unwrap(), time: NaiveDateTime::from_timestamp_opt(1689912359, 0).unwrap(), c5: 2.0, c6: 4.0, }; let bin: Vec<u8> = to_buffer(&person); let obj: Person = from_buffer(&bin).expect("should success"); assert_eq!(person, obj); }
Shared reference and circular reference can be serialized automatically, no duplicate data or recursion error.
Java
import org.apache.fury.*; import org.apache.fury.config.*; import java.util.*; public class ReferenceExample { public static class SomeClass { SomeClass f1; Map<String, String> f2; Map<String, String> f3; } public static Object createObject() { SomeClass obj = new SomeClass(); obj.f1 = obj; obj.f2 = ofHashMap("k1", "v1", "k2", "v2"); obj.f3 = obj.f2; return obj; } // mvn exec:java -Dexec.mainClass="org.apache.fury.examples.ReferenceExample" public static void main(String[] args) { Fury fury = Fury.builder().withLanguage(Language.XLANG) .withRefTracking(true).build(); fury.register(SomeClass.class, "example.SomeClass"); byte[] bytes = fury.serialize(createObject()); // bytes can be data serialized by other languages. System.out.println(fury.deserialize(bytes)); } }
Python
from typing import Dict import pyfury class SomeClass: f1: "SomeClass" f2: Dict[str, str] f3: Dict[str, str] fury = pyfury.Fury(ref_tracking=True) fury.register_class(SomeClass, type_tag="example.SomeClass") obj = SomeClass() obj.f2 = {"k1": "v1", "k2": "v2"} obj.f1, obj.f3 = obj, obj.f2 data = fury.serialize(obj) # bytes can be data serialized by other languages. print(fury.deserialize(data))
Golang
package main import furygo "github.com/apache/incubator-fury/fury/go/fury" import "fmt" func main() { type SomeClass struct { F1 *SomeClass F2 map[string]string F3 map[string]string } fury := furygo.NewFury(true) if err := fury.RegisterTagType("example.SomeClass", SomeClass{}); err != nil { panic(err) } value := &SomeClass{F2: map[string]string{"k1": "v1", "k2": "v2"}} value.F3 = value.F2 value.F1 = value bytes, err := fury.Marshal(value) if err != nil { } var newValue interface{} // bytes can be data serialized by other languages. if err := fury.Unmarshal(bytes, &newValue); err != nil { panic(err) } fmt.Println(newValue) }
JavaScript
import Fury, { Type } from '@furyjs/fury'; /** * @furyjs/hps use v8's fast-calls-api that can be called directly by jit, ensure that the version of Node is 20 or above. * Experimental feature, installation success cannot be guaranteed at this moment * If you are unable to install the module, replace it with `const hps = null;` **/ import hps from '@furyjs/hps'; const description = Type.object('example.foo', { foo: Type.string(), bar: Type.object('example.foo'), }); const fury = new Fury({ hps }); const { serialize, deserialize } = fury.registerSerializer(description); const data: any = { foo: 'hello fury', }; data.bar = data; const input = serialize(data); const result = deserialize(input); console.log(result.bar.foo === result.foo);
JavaScript Reference cannot be implemented because of rust ownership restrictions
Java
import org.apache.fury.*; import org.apache.fury.config.*; import org.apache.fury.serializers.BufferObject; import org.apache.fury.memory.MemoryBuffer; import java.util.*; import java.util.stream.Collectors; public class ZeroCopyExample { // mvn exec:java -Dexec.mainClass="io.ray.fury.examples.ZeroCopyExample" public static void main(String[] args) { Fury fury = Fury.builder().withLanguage(Language.XLANG).build(); List<Object> list = ofArrayList("str", new byte[1000], new int[100], new double[100]); Collection<BufferObject> bufferObjects = new ArrayList<>(); byte[] bytes = fury.serialize(list, e -> !bufferObjects.add(e)); // bytes can be data serialized by other languages. List<MemoryBuffer> buffers = bufferObjects.stream() .map(BufferObject::toBuffer).collect(Collectors.toList()); System.out.println(fury.deserialize(bytes, buffers)); } }
Python
import array import pyfury import numpy as np fury = pyfury.Fury() list_ = ["str", bytes(bytearray(1000)), array.array("i", range(100)), np.full(100, 0.0, dtype=np.double)] serialized_objects = [] data = fury.serialize(list_, buffer_callback=serialized_objects.append) buffers = [o.to_buffer() for o in serialized_objects] # bytes can be data serialized by other languages. print(fury.deserialize(data, buffers=buffers))
Golang
package main
import furygo "github.com/apache/incubator-fury/fury/go/fury"
import "fmt"
func main() {
fury := furygo.NewFury()
list := []interface{}{"str", make([]byte, 1000)}
buf := fury.NewByteBuffer(nil)
var bufferObjects []fury.BufferObject
fury.Serialize(buf, list, func(o fury.BufferObject) bool {
bufferObjects = append(bufferObjects, o)
return false
})
var newList []interface{}
var buffers []*fury.ByteBuffer
for _, o := range bufferObjects {
buffers = append(buffers, o.ToBuffer())
}
if err := fury.Deserialize(buf, &newList, buffers); err != nil {
panic(err)
}
fmt.Println(newList)
}
JavaScript
// Coming soon