| --- |
| title: References |
| sidebar_position: 50 |
| id: references |
| 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. |
| --- |
| |
| By default Fory treats every value as a separate copy — if the same object appears in two fields it gets serialized twice, and after deserialization you get two independent copies. Enable reference tracking when: |
| |
| - the same object instance is referenced from multiple places in the graph |
| - your data contains a circular structure (e.g. a node that points to itself) |
| - object identity must be preserved after a round trip |
| |
| Leave reference tracking off for plain tree-shaped data; it adds a small overhead. |
| |
| ## Step 1: Enable Reference Tracking on the `Fory` Instance |
| |
| ```ts |
| const fory = new Fory({ ref: true }); |
| ``` |
| |
| ## Step 2: Mark the Fields That Can Have Shared or Circular References |
| |
| For each field whose value may be shared or circular, call `.setTrackingRef(true)` on the field's schema: |
| |
| ```ts |
| const nodeType = Type.struct("example.node", { |
| value: Type.string(), |
| next: Type.struct("example.node").setNullable(true).setTrackingRef(true), |
| }); |
| ``` |
| |
| You need **both** the global flag and the field-level flag. Missing either one results in values being copied rather than referenced. |
| |
| ## Circular self-reference example |
| |
| ```ts |
| import Fory, { Type } from "@apache-fory/core"; |
| |
| const nodeType = Type.struct("example.node", { |
| name: Type.string(), |
| selfRef: Type.struct("example.node").setNullable(true).setTrackingRef(true), |
| }); |
| |
| const fory = new Fory({ ref: true }); |
| const { serialize, deserialize } = fory.register(nodeType); |
| |
| const node: any = { name: "root", selfRef: null }; |
| node.selfRef = node; |
| |
| const copy = deserialize(serialize(node)); |
| console.log(copy.selfRef === copy); // true |
| ``` |
| |
| ## Shared nested reference example |
| |
| ```ts |
| const innerType = Type.struct(501, { |
| value: Type.string(), |
| }); |
| |
| const outerType = Type.struct(502, { |
| left: Type.struct(501).setNullable(true).setTrackingRef(true), |
| right: Type.struct(501).setNullable(true).setTrackingRef(true), |
| }); |
| |
| const fory = new Fory({ ref: true }); |
| const { serialize, deserialize } = fory.register(outerType); |
| |
| const shared = { value: "same-object" }; |
| const copy = deserialize(serialize({ left: shared, right: shared })); |
| console.log(copy.left === copy.right); // true |
| ``` |
| |
| ## When to enable it |
| |
| Enable reference tracking when: |
| |
| - the same object instance is reused in multiple fields |
| - your graph can be cyclic |
| - identity preservation matters after deserialization |
| |
| Leave it disabled when: |
| |
| - the data is a plain tree |
| - you want the lowest overhead |
| - object identity does not matter |
| |
| ## Cross-Language Note |
| |
| Reference tracking is part of the Fory binary protocol and works across runtimes. Both sides must enable reference tracking and mark the same fields as reference-tracked for the behavior to be consistent. |
| |
| ## Related Topics |
| |
| - [Basic Serialization](basic-serialization.md) |
| - [Schema Evolution](schema-evolution.md) |
| - [Cross-Language](cross-language.md) |