Cameleer

Fory data format

The fory data format serializes values to and from the Apache Fory (formerly Fury) cross-language binary format, so Rust, Java, Python, Go and JavaScript services can share compact payloads.

Name: fory · Crate: cameleer-dataformats · Cargo feature: dataformats · Apache Camel: Fory

When to use it

  • Exchange compact binary payloads with services that already use Apache Fory's xlang mode.
  • Replace JSON on a hot path (queues, caches) with a faster, smaller binary encoding while keeping dynamic, schema-less values.
  • Read Fory records produced by a Java Camel route that uses fory with xlang enabled.

Marshal and unmarshal

directioninput bodyoutput body
marshalany value: null, boolean, integer, float, string, bytes, array, objectFory xlang bytes
unmarshalFory xlang bytesthe value

Mapping: integers are written as VAR_INT64 and every integer type reads back as an integer; floats as FLOAT64; strings as STRING (Latin-1 when every character fits, UTF-8 otherwise); bytes as BINARY; arrays as LIST; objects as MAP. An object with an @type key ("namespace.TypeName") is written as a named struct; reading such a struct needs its field list (structTypes) unless it was written in compatible mode, which carries the field names.

Marshal a string body as-is and you get a Fory STRING; to send a JSON document as a map, unmarshal: json first, as in the example.

Example

JSON to Fory and back. The byteCount header shows the binary size: 49 bytes for a 58-byte JSON document.

yaml example: fory-round-trip
- route:
    id: fory-round-trip
    from:
      uri: direct:fory
      steps:
        - unmarshal:
            json: {}
        - marshal:
            fory: {}
        - setHeader:
            name: byteCount
            simple: "${body.length()}"
        - unmarshal:
            fory: {}
        - marshal:
            json: {}
        - setBody:
            simple: "${header.byteCount} bytes: ${body}"
json
{"device": "edge-7", "readings": [21, 22, 23], "ok": true}
text
49 bytes: {"device":"edge-7","readings":[21,22,23],"ok":true}

Named structs in compatible mode: the type definition with field names travels with the data, so the reader needs no structTypes.

yaml example: fory-compatible-struct
- route:
    id: fory-struct
    from:
      uri: direct:fory-struct
      steps:
        - unmarshal:
            json: {}
        - marshal:
            fory:
              compatible: true
        - unmarshal:
            fory:
              compatible: true
        - marshal:
            json: {}
json
{"@type": "example.Person", "name": "Ada", "age": 36}
text
{"@type":"example.Person","age":36,"name":"Ada"}

Struct fields are written in snake_case-sorted order, so they come back sorted.

Rust DSL

rust
b.from("direct:fory-rust")
    .unmarshal_json()
    .marshal(DataFormatDefinition::new("fory"))
    .unmarshal(DataFormatDefinition::new("fory"))
    .marshal_json();

Options

optiondefaultdescription
refTrackingfalseWrite reference flags so repeated strings and containers become back references. Alias trackingRef.
compatiblefalseWrite @type objects as compatible structs with a shared type definition (field names included). compatibleMode: COMPATIBLE does the same.
structTypes(none)Field lists of named structs for reading non-compatible structs: example.Person=name,age;example.Address=city.
requireClassRegistrationfalseWith true, marshalling an @type not listed in structTypes fails.
xlangSpecCURRENTProtocol edition: CURRENT (current xlang specification) or LEGACY (Fory 0.10/0.11 layout). Readers detect the edition from the header.
threadSafe, allowAutoWiredFory, unmarshalTypeAccepted for Camel compatibility; no effect.

Differences from Apache Camel

Camel's fory format serializes Java objects (Java native mode by default, classes registered with Fory). This implementation speaks only the cross-language (xlang) protocol and works with dynamic values; Java native payloads are rejected on unmarshal. Configure the Java side with xlang enabled to interoperate.

Common questions

Is Fory smaller than JSON?

Usually: numbers are varints, there are no quotes or field names for lists, and strings are length-prefixed. Measure with your own payloads; small maps with long keys gain less.

Why does reading a struct fail with an unknown type?

A struct written without compatible mode has no field names in the data. Add structTypes: example.Person=name,age (field order as the writer sorted them), or write with compatible: true.

Found a problem?

If something on this page doesn't match what Cameleer does, or you hit a bug while building with it, please help fix it, whether you are a person or a coding agent: open an issue that describes what you saw, then fork the repository, fix it, add or update a test, run cargo test --workspace, and open a pull request. CONTRIBUTING.md explains the ground rules.

Edit this page on GitHub