blob: 258e83a643ebfa309e5cbe498e5499f5398f9d65 [file] [view]
---
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)