diff --git a/.agents/languages/java.md b/.agents/languages/java.md index ceb9273676..28c6ef0ebd 100644 --- a/.agents/languages/java.md +++ b/.agents/languages/java.md @@ -176,18 +176,21 @@ Load this file when changing anything under `java/` or when Java drives a cross- - If changes touch GraalVM bootstrap, serializer retention, native-image metadata, or `ObjectStreamSerializer` GraalVM behavior, verify the native-image build and run the produced binary; a plain Java compile is insufficient. - Put latest-JDK or virtual-thread tests in the latest-JDK test modules with the matching compiler/profile floor, and centralize runtime-version probing in existing compatibility utilities. - For JDK25+ zero-Unsafe work, preserve serializer-family selection by type and configuration. Do not switch a type from `ObjectStreamSerializer` or another Fory serializer family to `JavaSerializer`, a JDK stream fallback, or any broad `java.* Serializable` fallback by JDK version or no-arg-constructor shape. -- JDK25+ zero-Unsafe runtime support must distinguish launch shape. When Fory is on the module - path, use `--add-opens=java.base/java.lang.invoke=org.apache.fory.core`; when Fory is on the - classpath, use `--add-opens=java.base/java.lang.invoke=ALL-UNNAMED`. Missing this open is an - invalid access configuration, not a reason to open per-package JDK internals or switch - serializer/object-creation families. JPMS tests that validate named-module access should keep the - `org.apache.fory.core` target. -- Do not probe JDK25+ trusted-lookup availability and turn `_JDKAccess` field-access booleans false when the required `java.base/java.lang.invoke` open is missing. Keep those access flags true on JDK25+ and let the owning trusted-lookup path raise the configuration error. +- JDK25+ access must distinguish launch shape. Opening `java.base/java.lang.invoke` is not required + for normal launches while the current-JDK Unsafe fallback is available, but is recommended. It is + required for zero-Unsafe launches or when that fallback is unavailable. When Fory is on the + module path, target `org.apache.fory.core`; when Fory is on the classpath, target `ALL-UNNAMED`. + JPMS tests that validate named-module access should keep the `org.apache.fory.core` target. +- Do not probe JDK25+ trusted-lookup availability and turn `_JDKAccess` field-access booleans false + when the optional `java.base/java.lang.invoke` open is missing. Keep those access flags true on + JDK25+ and let `_Lookup` try the direct access path followed by the current-JDK Unsafe fallback. + Raise the access error only when both paths are unavailable. - Keep JDK25+ unsafe-removal implementation invariants in agent/design docs and tests, not user guides. User guides should document user actions such as `--sun-misc-unsafe-memory-access=deny` and `java.base/java.lang.invoke` opens; do not expose internal serializer names, owner-model rationale, or avoided fallback strategies there. - JDK25+ user docs must not require application module package opens for Fory private-field access. - The only required platform open is `java.base/java.lang.invoke`, targeted to `ALL-UNNAMED` for - classpath runs or `org.apache.fory.core` for module-path runs; application module package opens - are not part of this design. + The only platform open Fory recommends is `java.base/java.lang.invoke`, targeted to `ALL-UNNAMED` + for classpath runs or `org.apache.fory.core` for module-path runs. Describe it as not required but + recommended for normal launches, and required when Unsafe access is disabled or unavailable. + Application module package opens are not part of this design. - JDK25+ final-field user docs must not tell ordinary classes to implement `java.io.Serializable`. Fory supports ordinary non-Serializable classes; mention `Serializable` only for JDK serialization hook examples or `java.*` serializability checks. @@ -195,8 +198,9 @@ Load this file when changing anything under `java/` or when Java drives a cross- classes to records, no-arg constructors, or custom serializers. Keep user docs focused on the supported runtime setup and normal class model. - Do not create a separate JDK25+ support user-guide page for the Java runtime setup unless the - user explicitly asks for one. Keep the `java.base/java.lang.invoke` open in install-facing docs - such as the Java/Kotlin/Scala install sections and README. + user explicitly asks for one. Keep guidance that opening `java.base/java.lang.invoke` is not + required but recommended in install-facing docs such as the Java/Kotlin/Scala install sections + and README. - JDK25+ zero-Unsafe final-field writes must use a true target-class trusted lookup from the original `IMPL_LOOKUP`, not `IMPL_LOOKUP.in(type)`. JDK26+ normal Fory final-field restoration must pass with `--illegal-final-field-mutation=deny` and must not require `--enable-final-field-mutation`. - For JDK25+ object creation, do not use `sun.reflect.ReflectionFactory`, `jdk.unsupported`, or an Unsafe-backed object instantiator. Normal JVM no-constructor construction must use the @@ -205,8 +209,9 @@ Load this file when changing anything under `java/` or when Java drives a cross- constructor validation. ObjectStream-compatible serializers own the separate `ParentNoArgCtrInstantiator` path and must keep Java serialization parent-constructor rules. The JDK25+ ReflectionFactory path uses trusted-lookup access to `jdk.internal.reflect.ReflectionFactory` - in `java.base` and must not require `--add-opens=java.base/jdk.internal.reflect=...`; the only - JDK25+ platform open remains `java.base/java.lang.invoke=org.apache.fory.core`. GraalVM JDK25+ + in `java.base` and must not require `--add-opens=java.base/jdk.internal.reflect=...`; + `java.base/java.lang.invoke` remains the only platform open Fory may use, with the launch-shape + target described above. GraalVM JDK25+ native-image ordinary serializers may use an `ObjectStreamClass.newInstance` MethodHandle only for the exact Serializable case where the serialization constructor class is `Object`; that preserves normal empty-instance semantics because no user superclass constructor can run. For @@ -225,7 +230,13 @@ Load this file when changing anything under `java/` or when Java drives a cross- - `UnsafeObjectInstantiator` is the JDK8-24 Unsafe owner only. It must be a top-level instantiator with a Java25 multi-release stub that contains no Unsafe, ObjectStream, ReflectionFactory, or constructor-bypass implementation. -- Keep the Java25 `_Lookup` overlay unless a future refactor can merge it without exposing Unsafe to the JDK25 class graph. Root `_Lookup` uses Unsafe for the JDK8-24 trusted-lookup fast path, while Java25 `_Lookup` uses the required `java.lang.invoke` open. `DefineClass` is root-owned; when Java25+ generated serializers need hidden nestmate class definition, it must use cached method handles and reflective `Lookup.ClassOption.NESTMATE` loading so Java 8 through Java 14 can still load the root class safely. +- Keep the Java25 `_Lookup` overlay unless a future refactor can merge it without exposing Unsafe to + the JDK25 class graph. Root `_Lookup` uses Unsafe for the JDK8-24 trusted-lookup fast path, while + Java25 `_Lookup` first uses the optional `java.lang.invoke` open and falls back through the split + current-JDK Unsafe lookup when the open is absent. `DefineClass` is root-owned; when Java25+ + generated serializers need hidden nestmate class definition, it must use cached method handles + and reflective `Lookup.ClassOption.NESTMATE` loading so Java 8 through Java 14 can still load the + root class safely. - Treat `ByteArrayOutputStream` and `ByteArrayInputStream` as ordinary streams on every JDK. Do not restore private-buffer wrapping for JDK8-24 performance, because that reintroduces `java.base/java.io` private-field ownership and module-open requirements. @@ -272,12 +283,13 @@ Load this file when changing anything under `java/` or when Java drives a cross- focused on field and array access, keep serialization hook discovery in serializer-owned code, and keep `_JDKAccess` limited to JDK lookup, module, function factory, and access-flag primitives. -- JDK25+ serialization hook access must use the required trusted lookup from - `java.base/java.lang.invoke=org.apache.fory.core`. Keep `sun.reflect.ReflectionFactory` as a - JDK8-24 hook optimization only, and do not add per-type reflective escapes for hook invocation. +- JDK25+ serialization hook access must use the trusted lookup obtained through the optional + `java.lang.invoke` open or the existing current-JDK Unsafe fallback. Keep + `sun.reflect.ReflectionFactory` as a JDK8-24 hook optimization only, and do not add per-type + reflective escapes for hook invocation. - JDK25+ `PlatformStringUtils` getter methods sit behind `StringSerializer` static-final access - gates. Do not add per-call access checks in those getters; missing module opens should fail at - trusted-lookup initialization or cold setup, not inside string hot paths. + gates. Do not add per-call access checks in those getters; failures after both direct lookup and + the current-JDK Unsafe fallback should surface during cold setup, not inside string hot paths. - `FieldAccessor` owns field-accessor dispatch. `RecordFieldAccessors` owns record field access, and `InstanceFieldAccessors` owns non-record instance field access. Do not reintroduce a `FieldAccessorFactory` layer. Treat `InstanceFieldAccessors` as package-owned implementation diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5585589a19..3895ac645b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2043,13 +2043,27 @@ jobs: ref: main path: fory-site - - name: Set up Node.js 20.x + - name: Set up Node.js 24.x uses: actions/setup-node@v4 with: - node-version: 20.x + node-version: 24.x cache: npm cache-dependency-path: fory-site/package-lock.json + - name: Install fory-site dependencies + working-directory: fory-site + run: npm ci --prefer-offline --fund=false + + - name: Restore Docusaurus cache + uses: actions/cache@v4 + with: + path: fory-site/node_modules/.cache + key: ${{ runner.os }}-node24-docusaurus-${{ hashFiles('fory-site/package-lock.json') }} + + - name: Test fory-site validator + working-directory: fory + run: python3 -m unittest ci.test_validate_fory_site_sync + - name: Sync files and validate site build run: | python3 fory/ci/validate_fory_site_sync.py fory fory-site diff --git a/README.md b/README.md index 4a5e7bcb86..6951de3742 100644 --- a/README.md +++ b/README.md @@ -160,8 +160,9 @@ Gradle: implementation "org.apache.fory:fory-core:1.5.0" ``` -On JDK25+, open `java.lang.invoke` to Fory. Use `ALL-UNNAMED` when Fory is on -the classpath: +On JDK25+, opening `java.lang.invoke` to Fory core is not required, but is recommended. It avoids the +current-JDK Unsafe fallback and is required when Unsafe access is disabled or unavailable, including +with `--sun-misc-unsafe-memory-access=deny`. Use `ALL-UNNAMED` when Fory is on the classpath: ```bash --add-opens=java.base/java.lang.invoke=ALL-UNNAMED diff --git a/ci/test_validate_fory_site_sync.py b/ci/test_validate_fory_site_sync.py index d7856f4c3c..077c5e19dd 100644 --- a/ci/test_validate_fory_site_sync.py +++ b/ci/test_validate_fory_site_sync.py @@ -18,6 +18,7 @@ import pathlib import tempfile import unittest +from unittest import mock if __package__: from . import validate_fory_site_sync @@ -44,6 +45,77 @@ def test_rejects_forbidden_doc_roots(self): with self.assertRaisesRegex(RuntimeError, "must not be synced"): validate_fory_site_sync.parse_sync_mappings(sync_file) + def test_preserves_site_versions(self): + with tempfile.TemporaryDirectory() as directory: + root = pathlib.Path(directory) + fory_root = root / "fory" + site_root = root / "fory-site" + (fory_root / ".github").mkdir(parents=True) + (fory_root / "docs").mkdir() + (site_root / "docs").mkdir(parents=True) + (site_root / "versioned_docs" / "version-9.9.9").mkdir(parents=True) + (site_root / "versioned_sidebars").mkdir() + + (fory_root / ".github" / "sync.yml").write_text( + """apache/fory-site@main: + - source: docs/index.md + dest: docs/index.md +""", + encoding="utf-8", + ) + (fory_root / "docs" / "index.md").write_text("current\n", encoding="utf-8") + (site_root / "docs" / "index.md").write_text("old\n", encoding="utf-8") + versioned_doc = site_root / "versioned_docs" / "version-9.9.9" / "index.md" + versioned_doc.write_text("released\n", encoding="utf-8") + versioned_sidebar = ( + site_root / "versioned_sidebars" / "version-9.9.9-sidebars.json" + ) + versioned_sidebar.write_text("{}\n", encoding="utf-8") + versions_json = site_root / "versions.json" + versions_json.write_text('["9.9.9"]\n', encoding="utf-8") + config = site_root / "docusaurus.config.ts" + config.write_text("lastVersion: '9.9.9'\n", encoding="utf-8") + + with ( + mock.patch.object( + validate_fory_site_sync, + "parse_args", + return_value=mock.Mock( + fory_root=fory_root, fory_site_root=site_root + ), + ), + mock.patch.object(validate_fory_site_sync, "run_site_commands") as run, + ): + self.assertEqual(validate_fory_site_sync.main(), 0) + + run.assert_called_once_with(site_root) + self.assertEqual((site_root / "docs" / "index.md").read_text(), "current\n") + self.assertEqual(versioned_doc.read_text(), "released\n") + self.assertEqual(versioned_sidebar.read_text(), "{}\n") + self.assertEqual(versions_json.read_text(), '["9.9.9"]\n') + self.assertEqual(config.read_text(), "lastVersion: '9.9.9'\n") + + def test_uses_single_locale_build(self): + site_root = pathlib.Path("fory-site") + with mock.patch.object(validate_fory_site_sync.subprocess, "run") as run: + validate_fory_site_sync.run_site_commands(site_root) + + self.assertEqual( + run.call_args_list, + [ + mock.call( + ("npm", "run", "lint", "--if-present"), + cwd=site_root, + check=True, + ), + mock.call( + ("npm", "run", "build", "--", "--locale", "en-US"), + cwd=site_root, + check=True, + ), + ], + ) + if __name__ == "__main__": unittest.main() diff --git a/ci/validate_fory_site_sync.py b/ci/validate_fory_site_sync.py index 83794e2f8b..ea7ca73309 100644 --- a/ci/validate_fory_site_sync.py +++ b/ci/validate_fory_site_sync.py @@ -26,9 +26,7 @@ from typing import List, Tuple TARGET_REPO = "apache/fory-site@main" -FORBIDDEN_SYNC_ROOTS = ( - pathlib.PurePosixPath("docs/security"), -) +FORBIDDEN_SYNC_ROOTS = (pathlib.PurePosixPath("docs/security"),) def is_forbidden_sync_path(path: str) -> bool: @@ -102,76 +100,12 @@ def sync_files( print(f"synced {source} -> {dest}") -def rewrite_versions_block(text: str) -> str: - marker = "versions:" - idx = text.find(marker) - if idx == -1: - return text - - brace_start = text.find("{", idx) - if brace_start == -1: - return text - - depth = 0 - end = -1 - i = brace_start - while i < len(text): - ch = text[i] - if ch == "{": - depth += 1 - elif ch == "}": - depth -= 1 - if depth == 0: - end = i - break - i += 1 - - if end == -1: - return text - - j = end + 1 - while j < len(text) and text[j].isspace(): - j += 1 - if j < len(text) and text[j] == ",": - j += 1 - - replacement = ( - "versions: {\n" - " current: {\n" - " label: 'dev',\n" - " },\n" - " }," - ) - return text[:idx] + replacement + text[j:] - - -def patch_docusaurus_config(path: pathlib.Path) -> None: - if not path.exists(): - return - text = path.read_text(encoding="utf-8") - text = re.sub(r"locales:\s*\[[^\]]*\]", "locales: ['en-US']", text, count=1) - text = re.sub(r"lastVersion:\s*'[^']*'", "lastVersion: 'current'", text) - text = rewrite_versions_block(text) - path.write_text(text, encoding="utf-8") - - -def prune_for_fast_build(site_root: pathlib.Path) -> None: - for directory in ("i18n", "versioned_docs", "versioned_sidebars"): - shutil.rmtree(site_root / directory, ignore_errors=True) - - versions_json = site_root / "versions.json" - if versions_json.exists(): - versions_json.write_text("[]\n", encoding="utf-8") - - patch_docusaurus_config(site_root / "docusaurus.config.ts") - patch_docusaurus_config(site_root / "docusaurus.config.js") - - def run_site_commands(site_root: pathlib.Path) -> None: + # Limit rendering without rewriting the site's released-version state. The normal build command + # also preserves site-owned Docusaurus acceleration such as `future.faster`. for command in ( - ("npm", "install"), ("npm", "run", "lint", "--if-present"), - ("npm", "run", "build"), + ("npm", "run", "build", "--", "--locale", "en-US"), ): subprocess.run(command, cwd=site_root, check=True) @@ -197,7 +131,6 @@ def main() -> int: raise FileNotFoundError(f"fory-site directory not found: {site_root}") sync_files(fory_root, site_root, sync_file) - prune_for_fast_build(site_root) run_site_commands(site_root) return 0 diff --git a/docs/benchmarks/index.md b/docs/benchmarks/index.md index f9a50cc987..0b38f7ef8d 100644 --- a/docs/benchmarks/index.md +++ b/docs/benchmarks/index.md @@ -128,6 +128,6 @@ Note: Results depend on hardware, dataset, and runtime versions. See the ## Read Results Responsibly -Start with [Methodology](methodology.md), then open the report whose capability, runtime, schema, +Start with [Methodology](methodology.md), then open the report whose capability, language, schema, mode, and operation match your workload. The checked-in results are historical evidence from their recorded environment, not a guarantee for a different application or current main branch. diff --git a/docs/benchmarks/json/_category_.json b/docs/benchmarks/json/_category_.json index d6cdf1f1b1..5c71869ca6 100644 --- a/docs/benchmarks/json/_category_.json +++ b/docs/benchmarks/json/_category_.json @@ -1,5 +1,6 @@ { "position": 4, + "key": "benchmark-json", "label": "Fory JSON", "collapsible": true, "collapsed": true diff --git a/docs/benchmarks/methodology.md b/docs/benchmarks/methodology.md index 4cf3f2cc31..fbd9c8afc5 100644 --- a/docs/benchmarks/methodology.md +++ b/docs/benchmarks/methodology.md @@ -36,7 +36,7 @@ comparing different semantics as if they were equivalent. Compare one operation and equivalent data semantics. Do not compare an xlang payload with a native payload or a full object reconstruction with Row Format field access without naming that semantic -difference. JIT- and codegen-based runtimes require representative warm-up. +difference. JIT- and codegen-based implementations require representative warm-up. Run the active benchmark harness for decisions that depend on current code. Checked-in reports are evidence for the commit and environment they record. diff --git a/docs/benchmarks/object-serialization/_category_.json b/docs/benchmarks/object-serialization/_category_.json index 517dab897e..9e88c4d51a 100644 --- a/docs/benchmarks/object-serialization/_category_.json +++ b/docs/benchmarks/object-serialization/_category_.json @@ -1,5 +1,6 @@ { "position": 3, + "key": "benchmark-object-serialization", "label": "Object Serialization", "collapsible": true, "collapsed": true diff --git a/docs/compiler/generated-code/index.md b/docs/compiler/generated-code/index.md index ac9908fa7b..a8a872d872 100644 --- a/docs/compiler/generated-code/index.md +++ b/docs/compiler/generated-code/index.md @@ -156,12 +156,12 @@ union Wrapper { | Swift | `toBytes` / `fromBytes` | | Dart | (via `fory.serialize()`) | -## Runtime References +## Language References -Choose the generated-code reference for the output runtime. Generated models remain ordinary -runtime-owned types and use that runtime's supported Fory serialization APIs. +Choose the generated-code reference for the target language. Generated models remain ordinary +language-native types and use the supported Fory serialization APIs for that language. -| Runtime | Generated-code reference | +| Language | Generated-code reference | | --------------------- | -------------------------------------- | | Java | [Java](java.md) | | Python | [Python](python.md) | diff --git a/docs/compiler/index.md b/docs/compiler/index.md index 21590e64d6..15dac27c4f 100644 --- a/docs/compiler/index.md +++ b/docs/compiler/index.md @@ -96,7 +96,7 @@ foryc animals.fdl --java_out=./generated/java --python_out=./generated/python -- ``` The generated service code uses normal gRPC APIs, but request and response -objects are serialized with Fory. See [Fory gRPC](../grpc/index.md) for runtime +objects are serialized with Fory. See [Fory gRPC](../grpc/index.md) for language-specific dependencies, server and client setup, streaming modes, browser support, and interoperability boundaries. diff --git a/docs/development/index.md b/docs/development/index.md index 1584659bb0..f1b25de373 100644 --- a/docs/development/index.md +++ b/docs/development/index.md @@ -129,7 +129,7 @@ Requirements: See [Debugging C++](cpp-debugging.md) for the repository's VS Code, Bazel, LLDB, and GDB setup. -Runtime-specific contributor instructions remain in each runtime's source tree and contributor +Language-specific contributor instructions remain in each language's source tree and contributor README when they are not part of the shared repository build. ## Contributing diff --git a/docs/grpc/cpp.md b/docs/grpc/cpp.md index 499cb51c1c..c5d87e947d 100644 --- a/docs/grpc/cpp.md +++ b/docs/grpc/cpp.md @@ -114,7 +114,7 @@ For this schema, the C++ generator emits: Include the generated gRPC header from application code and compile `demo_greeter.service.grpc.cc` once in your build target. The codec is generated -directly in the gRPC header; there is no separate Fory gRPC runtime source file. +directly in the gRPC header; there is no separate Fory gRPC support source file. ## Implement a Server @@ -245,7 +245,7 @@ the final status. The generated descriptors preserve the exact IDL service and method names for the gRPC path. -## gRPC Runtime Behavior +## gRPC Stack Behavior The generated service companion only supplies Fory serialization and gRPC C++ bindings. Operational behavior remains standard gRPC C++ behavior: diff --git a/docs/grpc/csharp.md b/docs/grpc/csharp.md index fb468cf831..06997d1e7b 100644 --- a/docs/grpc/csharp.md +++ b/docs/grpc/csharp.md @@ -284,7 +284,7 @@ A gRPC service named `Greeter` still generates the service companion schema files target the same C# namespace without colliding. No namespace-derived or service-derived module alias is generated. -## gRPC Runtime Behavior +## gRPC Stack Behavior The generated service code only replaces request and response serialization. All normal gRPC operational features still belong to your gRPC stack: diff --git a/docs/grpc/go.md b/docs/grpc/go.md index b3551d96a1..ee3ec18d75 100644 --- a/docs/grpc/go.md +++ b/docs/grpc/go.md @@ -201,7 +201,7 @@ Generated Go code follows grpc-go conventions: - The generated codec is used for every message frame, including streaming frames. -## gRPC Runtime Behavior +## gRPC Stack Behavior The generated service companion only supplies Fory serialization. Operational behavior remains standard grpc-go behavior: diff --git a/docs/grpc/index.md b/docs/grpc/index.md index a0c4712e0a..0aae10ce69 100644 --- a/docs/grpc/index.md +++ b/docs/grpc/index.md @@ -25,7 +25,7 @@ the Fory compiler. The payload marshaller uses Fory rather than protobuf message ## When to Use It Use Fory gRPC when every peer is generated from the same Fory IDL, protobuf IDL, or FlatBuffers IDL -contract and supports the matching Fory runtime. Use ordinary protobuf gRPC when generic protobuf +contract and supports the matching Fory implementation for its language. Use ordinary protobuf gRPC when generic protobuf clients, reflection tools, or protobuf message bytes are required. ## Schema Frontends @@ -45,7 +45,7 @@ project build. 1. Define messages and services in a supported compiler frontend. 2. Generate models and gRPC companions with `foryc`. -3. Add the normal gRPC dependencies for the selected runtime. +3. Add the normal gRPC dependencies for the selected language. 4. Implement the generated server base and call the generated client. 5. Verify unary and streaming calls between generated peers. @@ -62,19 +62,19 @@ generated request and response models. ### Ownership Boundary -Fory can generate service companions for application-provided gRPC runtimes. Those companions +Fory can generate service companions for application-provided gRPC implementations. Those companions provide Fory serialization for request and response objects; the application and gRPC stack still own listeners, channels, credentials, authentication, authorization, deadlines, retries, and transport lifecycle. Fory packages do not add a gRPC implementation as a hard dependency. The application selects and -configures the runtime's gRPC libraries. +configures its gRPC libraries. ### Generated Service Surface -The compiler emits runtime-idiomatic service bases, clients or stubs, method metadata, and Fory +The compiler emits language-idiomatic service bases, clients or stubs, method metadata, and Fory marshallers. Model generation is documented under -[Generated Code](../compiler/generated-code/index.md); the runtime pages document server and client +[Generated Code](../compiler/generated-code/index.md); the language pages document server and client integration. ## Interoperability @@ -94,13 +94,13 @@ Test at least one unary call and every streaming shape used by the service. A pr `UNIMPLEMENTED` or decode failure usually means the peer used an ordinary protobuf stub or a different generated service contract. -## Runtime Guides +## Language Guides Java, Python, C++, Go, Rust, JavaScript/TypeScript, C#, Dart, Scala, and Kotlin have documented gRPC -companions. Use the [support matrix](../introduction/support-matrix.md) and the selected runtime page +companions. Use the [support matrix](../introduction/support-matrix.md) and the selected language page for current dependencies and streaming support. -| Runtime | Guide | +| Language | Guide | | --------------------- | ------------------------------------- | | Java | [Java](java.md) | | Python | [Python](python.md) | diff --git a/docs/grpc/java.md b/docs/grpc/java.md index 555a029e81..96f92952cd 100644 --- a/docs/grpc/java.md +++ b/docs/grpc/java.md @@ -366,7 +366,7 @@ final class StreamingClient { The generated descriptors preserve the exact IDL service and method names for the gRPC path. -## gRPC Runtime Behavior +## gRPC Stack Behavior The generated service code only replaces request and response serialization. All normal gRPC operational features still belong to grpc-java: diff --git a/docs/grpc/javascript.md b/docs/grpc/javascript.md index 2c0a623007..3f4c94faa9 100644 --- a/docs/grpc/javascript.md +++ b/docs/grpc/javascript.md @@ -291,7 +291,7 @@ stream.on("end", () => { }); ``` -## gRPC Runtime Behavior +## gRPC Stack Behavior Generated service code only replaces request and response serialization. Normal gRPC operational features still belong to the transport package: diff --git a/docs/grpc/kotlin.md b/docs/grpc/kotlin.md index 09f87223d0..5cfc682f81 100644 --- a/docs/grpc/kotlin.md +++ b/docs/grpc/kotlin.md @@ -230,7 +230,7 @@ stub.chat( } ``` -## gRPC Runtime Behavior +## gRPC Stack Behavior The generated service code only replaces request and response serialization. All normal gRPC operational features still belong to grpc-java and diff --git a/docs/grpc/python.md b/docs/grpc/python.md index c8bb3f69d4..0d271023b2 100644 --- a/docs/grpc/python.md +++ b/docs/grpc/python.md @@ -279,7 +279,7 @@ with grpc.insecure_channel("localhost:50051") as channel: Sync streaming follows the normal `grpcio` iterator and generator conventions. -## gRPC Runtime Behavior +## gRPC Stack Behavior The generated service companion only supplies Fory serialization callbacks. Operational behavior remains standard `grpcio` behavior: diff --git a/docs/grpc/rust.md b/docs/grpc/rust.md index fe2d2b775f..4ddaf3dd64 100644 --- a/docs/grpc/rust.md +++ b/docs/grpc/rust.md @@ -300,7 +300,7 @@ reference metadata for a request or response type, Rust gRPC generation rejects that service. Use thread-safe reference shapes for gRPC payloads, or keep the non-thread-safe type out of the RPC boundary. -## gRPC Runtime Behavior +## gRPC Stack Behavior The generated service companion only supplies Fory serialization and tonic bindings. Operational behavior remains standard tonic behavior: diff --git a/docs/grpc/scala.md b/docs/grpc/scala.md index 43e9386b3e..43d5122b26 100644 --- a/docs/grpc/scala.md +++ b/docs/grpc/scala.md @@ -371,7 +371,7 @@ Server-streaming, client-streaming, and bidirectional server methods use grpc-java `StreamObserver` APIs because streaming completion, request flow control, cancellation, and backpressure follow grpc-java behavior. -## gRPC Runtime Behavior +## gRPC Stack Behavior The generated service code only replaces request and response serialization. All normal gRPC operational features still belong to grpc-java: diff --git a/docs/grpc/troubleshooting.md b/docs/grpc/troubleshooting.md index 916e816bb2..71c0c163cf 100644 --- a/docs/grpc/troubleshooting.md +++ b/docs/grpc/troubleshooting.md @@ -19,7 +19,7 @@ license: | limitations under the License. --- -Use the selected runtime guide for dependency- and API-specific diagnostics. +Use the selected language guide for dependency- and API-specific diagnostics. ## `UNIMPLEMENTED` @@ -33,5 +33,5 @@ separate ordinary protobuf service. ## A generated file does not compile -Check the runtime page's required gRPC packages and versions, then regenerate all model and service +Check the language page's required gRPC packages and versions, then regenerate all model and service files with the same compiler version. diff --git a/docs/index.md b/docs/index.md index 4bbf46e35a..49ca9e7074 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,7 +25,7 @@ rows, standard JSON, schema-driven models, and Fory-backed gRPC services. ## Start here 1. Read the [Introduction](introduction/index.md) and [choose a format](introduction/choose-a-format.md). -2. Install the selected runtime from [Getting Started](start/index.md). +2. Install Fory for the selected language from [Getting Started](start/index.md). 3. Review [Benchmarks](benchmarks/index.md) and their methodology for relevant performance evidence. 4. Continue with the owning capability guide. @@ -33,15 +33,15 @@ rows, standard JSON, schema-driven models, and Fory-backed gRPC services. | Capability | Use it for | Documentation | | --------------------- | ---------------------------------------------------- | ----------------------------------------------------- | -| Object Serialization | Reconstruct xlang or runtime-native object graphs | [Object Serialization](object-serialization/index.md) | +| Object Serialization | Reconstruct xlang or language-native object graphs | [Object Serialization](object-serialization/index.md) | | Row Format | Random and partial access to trusted analytical data | [Row Format](row-format/index.md) | | Fory JSON | High-throughput standard JSON mapped to Java objects | [Fory JSON](json/index.md) | -| Fory IDL and compiler | Generate runtime-native models from a shared schema | [Compiler](compiler/index.md) | +| Fory IDL and compiler | Generate language-native models from a shared schema | [Compiler](compiler/index.md) | | Fory gRPC | Generate gRPC companions that marshal Fory models | [Fory gRPC](grpc/index.md) | -## Runtime documentation +## Language guides -Binary Object Serialization provides multi-page runtime guides for +Binary Object Serialization provides multi-page language guides for [Java](object-serialization/java/index.md), [Python](object-serialization/python/index.md), [C++](object-serialization/cpp/index.md), [Go](object-serialization/go/index.md), [Rust](object-serialization/rust/index.md), diff --git a/docs/introduction/choose-a-format.md b/docs/introduction/choose-a-format.md index 240590d1c5..f2fb2683c6 100644 --- a/docs/introduction/choose-a-format.md +++ b/docs/introduction/choose-a-format.md @@ -21,8 +21,8 @@ license: | | Format or mode | Data model | Use it when | Interoperability | Start here | | -------------- | ------------------------------------ | ------------------------------------------------------------- | --------------------------------------------------------------------------- | -------------------------------------------------------- | -| Xlang binary | Portable object graphs | Data crosses language boundaries | Shared wire format across supported runtimes | [Cross-language guide](../object-serialization/xlang.md) | -| Native binary | Runtime-native object graphs | Producer and consumer use the same language | Same runtime family only | [Object Serialization](../object-serialization/index.md) | +| Xlang binary | Portable object graphs | Data crosses language boundaries | Shared wire format across supported Fory implementations | [Cross-language guide](../object-serialization/xlang.md) | +| Native binary | Language-native object graphs | Producer and consumer use one Fory implementation family | One Fory implementation family only | [Object Serialization](../object-serialization/index.md) | | Row Format | Random-access binary rows | You need random field access or analytics-style partial reads | Standard Row is shared by Java, Python, C++, and Rust; Compact is Java-only | [Row Format guide](../row-format/index.md) | | Fory JSON | Standard JSON mapped to Java objects | Java applications need high-performance standard JSON | Standard JSON text | [Fory JSON guide](../json/index.md) | @@ -30,12 +30,12 @@ Xlang and native are sibling modes of Object Serialization. Use them when the re reconstruct an object graph. Row Format and Fory JSON are separate formats, not additional Object Serialization modes. -For Java, Scala, Kotlin, Python, C++, Go, and Rust, use native mode for -same-language traffic. It avoids xlang's cross-language type mapping and +For Java, Scala, Kotlin, Python, C++, Go, and Rust, use native mode for traffic +within one Fory implementation family. It avoids xlang's cross-language type mapping and metadata constraints, stays closer to each language's native type system, and supports broader language-specific object graphs. Use it when both producer and -consumer are in the same language family and you want the native object model -rather than a portable cross-language schema. +consumer use the same native wire format and you want the native object model rather than a +portable cross-language schema. For Java/JVM-only systems, native mode is the replacement path for JDK serialization, Kryo, FST, Hessian, and Java-only Protocol Buffers payloads. For @@ -66,7 +66,7 @@ contract; it generates models that use the relevant Fory capability. ## Related capabilities -[Fory IDL and the compiler](../compiler/index.md) generate native models for supported runtimes. +[Fory IDL and the compiler](../compiler/index.md) generate native models for supported languages. Service definitions can also generate [Fory gRPC](../grpc/index.md) code. Neither capability defines another serialization format. diff --git a/docs/introduction/index.md b/docs/introduction/index.md index 2245ef3700..74d4b16741 100644 --- a/docs/introduction/index.md +++ b/docs/introduction/index.md @@ -23,9 +23,9 @@ license: | idiomatic domain objects, schema IDL, and cross-language data exchange. Fory is built for compact, high-throughput serialization across languages and -runtimes. It works directly with application objects, supports shared schemas +execution platforms. It works directly with application objects, supports shared schemas when you need a stable contract, and preserves object graph features such as -shared references, circular references, and polymorphic runtime types. +shared references, circular references, and concrete types for polymorphic values. ## Quick Example @@ -82,7 +82,7 @@ exchanges compact binary payloads across supported languages: - **Compact metadata**: Type metadata and field information are packed to keep payloads small. - **Schema evolution**: Compatible mode supports forward and backward evolution for application schemas. -- **Object graph semantics**: Shared references, circular references, and polymorphic runtime types are preserved across runtimes. +- **Object graph semantics**: Shared references, circular references, and concrete types for polymorphic values are preserved across languages. - **Type mapping**: Language-specific values are mapped through the shared [type mapping](../specification/xlang_type_mapping.md). ### Domain Objects First @@ -103,7 +103,7 @@ once and generate native domain objects for each target language: - Model numbers, strings, lists, maps, arrays, enums, structs, and unions. - Express shared and circular references directly in the schema. - Generate idiomatic host-language code without introducing transport-specific wrapper types into user code. -- Use schema IDL when services need a stable contract across independently maintained runtimes. +- Use schema IDL when services need a stable contract across independently maintained Fory implementations. ### Row-Format Random Access @@ -115,11 +115,11 @@ optimized for analytics and partial-read workloads: - **Apache Arrow integration**: Convert to columnar data for analytics pipelines. - **Multi-language support**: Exchange Standard Row Format data across Java, Python, C++, and Rust. -### Optimized Runtimes +### Optimized Fory Implementations -Fory keeps hot paths fast without making every runtime use the same implementation strategy: +Fory keeps hot paths fast without making every Fory implementation use the same strategy: - **Java JIT serializers**: Runtime code generation eliminates reflection overhead and inlines hot paths. -- **Generated and static serializers**: Other runtimes use generated or static serializers where appropriate. +- **Generated and static serializers**: Other Fory implementations use generated or static serializers where appropriate. - **Zero-copy paths**: Row format and out-of-band buffers avoid unnecessary copies for large values. - **Metadata sharing**: Repeated type information is shared or packed to reduce serialization overhead. diff --git a/docs/introduction/support-matrix.md b/docs/introduction/support-matrix.md index 7fee55a395..953619cd93 100644 --- a/docs/introduction/support-matrix.md +++ b/docs/introduction/support-matrix.md @@ -19,13 +19,13 @@ license: | limitations under the License. --- -Use this matrix to confirm the documented API surface before choosing a capability. A runtime page +Use this matrix to confirm the documented API surface before choosing a capability. A language page does not imply support for every Fory capability. -| Capability | Documented runtimes | Interoperability | +| Capability | Documented languages | Interoperability | | --------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------- | | Xlang object serialization | Java, Python, C++, Go, Rust, JavaScript/TypeScript, C#, Swift, Dart, Scala, Kotlin | One shared xlang wire format | -| Native object serialization | Java, Python, C++, Go, Rust, Scala, Kotlin | Same runtime family only | +| Native object serialization | Java, Python, C++, Go, Rust, Scala, Kotlin | One Fory implementation family only | | Standard Row Format | Java, Python, C++, Rust | Shared Standard Row layout | | Compact Row Format | Java | Java-only compact layout | | Fory JSON | Java | Standard JSON text | diff --git a/docs/json/android.md b/docs/json/android.md index 2cca186e35..54488f5561 100644 --- a/docs/json/android.md +++ b/docs/json/android.md @@ -23,7 +23,7 @@ Fory JSON supports ordinary classes on Android API level 26 and later through th `fory-json` artifact. Runtime JSON code generation and asynchronous compilation are disabled automatically, so `ForyJson.builder().build()` uses the interpreted object mapper. -## Installation and Runtime Model +## Installation and Codec Model Add Fory JSON to the application: @@ -92,7 +92,7 @@ public final class Invoice { ## Mixins The same processor supports Fory JSON Mixins. A Mixin declares one exact target and is registered -on the runtime that should use it: +on the `ForyJson` builder that should use it: ```java import org.apache.fory.json.ForyJson; @@ -109,8 +109,8 @@ ForyJson json = ``` Compile every non-empty Mixin source with `fory-annotation-processor`. The processor emits exact -R8 rules and any pair-specific target operations that the runtime can use. Registered codecs, -effective type codecs, and built-in mappings keep their normal runtime precedence. An empty Mixin +R8 rules and any pair-specific target operations that the built `ForyJson` instance can use. Registered codecs, +effective type codecs, and built-in mappings keep their normal codec-selection precedence. An empty Mixin produces no generated output. A Mixin may place `JsonValidator` on a public abstract zero-argument `void` method that exactly @@ -118,13 +118,13 @@ matches a public target method. The generated pair calls that target method dire does not need `JsonType` solely for a Mixin validator. The target does not need `JsonType` merely because it has a Mixin. `JsonMixin` is itself the -processor entry point for the pair. If a target also uses `JsonType`, the runtime selects the +processor entry point for the pair. If a target also uses `JsonType`, the built `ForyJson` instance selects the pair-specific companion for a non-empty registered Mixin instead of combining the overlay with the target's direct companion. -Only one source is enabled for an exact target in one built runtime. A later registration for that +Only one source is enabled for an exact target in one built `ForyJson` instance. A later registration for that target replaces an earlier registration on the builder, and `build()` snapshots the selected -mapping. The processor may generate artifacts for multiple source alternatives; the runtime uses +mapping. The processor may generate artifacts for multiple source alternatives; the built instance uses only the last registered source. Use the processor-generated R8 rules for non-empty Mixins instead of broad package keep rules. diff --git a/docs/json/annotations.md b/docs/json/annotations.md index 5d3a2dd590..9b91c3d898 100644 --- a/docs/json/annotations.md +++ b/docs/json/annotations.md @@ -28,7 +28,7 @@ Fory JSON APIs, not Jackson, Gson, or Fory binary-protocol compatibility annotat `JsonType` asks the annotation processor to generate direct property and creator operations plus exact retention rules on the JVM and Android. It is not inherited, so annotate each eligible -concrete model that needs a generated companion on those runtimes. A directly annotated +concrete model that needs a generated companion on those platforms. A directly annotated `JsonValue` Record also receives a companion for its value accessor and canonical constructor. Ordinary unannotated classes may still use reflection; on Android they need application-authored exact R8 rules. Android-desugared Records require processor-generated operations from either a @@ -692,7 +692,7 @@ entry has a case-sensitive logical JSON name and exactly one trusted Java type s `className` is useful when an API JAR must not depend on an implementation JAR. It is resolved by the fixed builder class loader when the table is built. JSON input never supplies a Java class name -and cannot add entries. Runtime registration and open subtype discovery are not supported. +and cannot add entries. Post-build subtype registration and open subtype discovery are not supported. The default `PROPERTY` inclusion writes an inline discriminator as the first output member: diff --git a/docs/json/getting-started.md b/docs/json/getting-started.md index 6f715de28d..4c451f7438 100644 --- a/docs/json/getting-started.md +++ b/docs/json/getting-started.md @@ -46,7 +46,9 @@ Use the same version for every Fory module in one application. ### JDK 25 and later -On JDK 25 and later, open `java.lang.invoke` to Fory core. For a classpath application: +On JDK 25 and later, opening `java.lang.invoke` to Fory core is not required, but is recommended. It avoids +the current-JDK Unsafe fallback and is required when Unsafe access is disabled or unavailable, +including with `--sun-misc-unsafe-memory-access=deny`. For a classpath application: ```bash --add-opens=java.base/java.lang.invoke=ALL-UNNAMED diff --git a/docs/json/graalvm.md b/docs/json/graalvm.md index 25cc88731d..8c01c2831e 100644 --- a/docs/json/graalvm.md +++ b/docs/json/graalvm.md @@ -95,7 +95,7 @@ needed, and the provider package does not need to be exported or opened to Fory. methods and fields are not supported. Only configurations returned by a provider receive generated codecs. The default configuration is -not generated implicitly. If a codegen-enabled runtime configuration was not included, Fory JSON +not generated implicitly. If a codegen-enabled `ForyJson` configuration was not included, Fory JSON uses its prepared interpreted codecs and logs one process-wide warning recommending a reachable `@ForyJsonProvider`. `withCodegen(false)` explicitly selects interpreted codecs and does not request generated-codec lookup. Asynchronous compilation is disabled in a native executable. @@ -132,17 +132,17 @@ it does for a direct `JsonType` model. A provider configuration generates the Mi target only when that exact Mixin is registered in the returned `ForyJson`. Only one source is enabled for an exact target in a built `ForyJson`. Later registration replaces -an earlier source for subsequent `build()` calls; a runtime keeps the immutable snapshot it was +an earlier source for subsequent `build()` calls; each built `ForyJson` instance keeps the immutable snapshot it was built with. ## Type Discovery and Construction The `fory-json` artifact activates its Native Image Feature automatically. `@JsonType` is not -inherited, so annotate every concrete runtime model. An annotated base with a class-literal +inherited, so annotate every concrete application model. An annotated base with a class-literal `@JsonSubTypes` table registers its listed subtypes automatically. Dedicated supported containers, including `EnumMap` and `EnumSet`, use their built-in factories. Other reachable concrete `Collection` and `Map` root types require a public no-argument constructor. A class referenced only -by a runtime string is not reachable; +by a class name resolved at runtime is not reachable; `JsonSubTypes.Type.className` is therefore unsupported in a native image. Do not add application reflection configuration as a replacement for the generated configuration. diff --git a/docs/json/index.md b/docs/json/index.md index 47a2e3683f..9e6dc17edf 100644 --- a/docs/json/index.md +++ b/docs/json/index.md @@ -21,8 +21,7 @@ license: | Fory JSON is Apache Fory's thread-safe Java JSON codec. It provides interpreted and runtime-generated codecs for Java objects, records, immutable creator-based classes, common JDK -types, generic containers, custom complete-value codecs, and finite annotation-declared -polymorphism. +types, generic containers, and custom complete-value codecs. Fory JSON is a separate data format from Fory's binary native and xlang protocols. Use it when a system must exchange ordinary JSON with browsers, APIs, logs, configuration, or another JSON @@ -31,34 +30,34 @@ reference identity, circular graphs, or Fory's binary-only features. ## Documentation map -| Goal | Page | -| ---------------------------------------------------------------- | ------------------------------------- | -| First runnable JSON round trip | [Getting Started](getting-started.md) | -| Understand Java object mapping and configuration | [Object Mapping](object-mapping.md) | -| Configure properties, creators, values, validators, and subtypes | [Annotations](annotations.md) | -| Extend complete values, children, and map keys | [Custom Codecs](custom-codecs.md) | -| Deploy on Android | [Android](android.md) | -| Build a GraalVM native image | [GraalVM Native Image](graalvm.md) | -| Decode input safely | [Security](security.md) | -| Diagnose failures | [Troubleshooting](troubleshooting.md) | +| Goal | Page | +| -------------------------------------------------------------- | ------------------------------------- | +| First runnable JSON round trip | [Getting Started](getting-started.md) | +| Understand Java object mapping and configuration | [Object Mapping](object-mapping.md) | +| Configure properties, creators, values, validators, and mixins | [Annotations](annotations.md) | +| Extend complete values, children, and map keys | [Custom Codecs](custom-codecs.md) | +| Deploy on Android | [Android](android.md) | +| Build a GraalVM native image | [GraalVM Native Image](graalvm.md) | +| Decode input safely | [Security](security.md) | +| Diagnose failures | [Troubleshooting](troubleshooting.md) | -## Limits and unsupported features +## Performance -Fory JSON intentionally has a smaller semantic surface than the Fory binary protocol and general -Jackson object mapping: +The Java JSON benchmark compares fory-json, Jackson, and Gson with the same data. Results below are +single-threaded throughput measurements on an Apple M4 Pro with JDK 26.0.1; higher is better. See +the [complete benchmark report](../benchmarks/json/java/README.md) for the command, environment, and +measurement configuration. -- no shared-reference identity or circular-reference protocol; -- no open polymorphism, JSON class-name IDs, runtime subtype discovery, or runtime subtype table - extension; -- no `InputStream` parser or incremental `OutputStream` writer on the `ForyJson` root API; -- no pretty-print configuration; -- no Jackson/Gson annotation compatibility layer; -- no aliases, views, filters, injection, managed/back references, object identity annotations, or - root wrapping; -- no Fory core `Expose` processing. +![Java JSON String benchmark throughput](../benchmarks/json/java/string_throughput.png) -Circular graphs eventually fail `maxDepth`; they are not reconstructed. Use Fory core's binary -native or xlang protocol when reference identity or cycles are required. +![Java JSON UTF-8 bytes benchmark throughput](../benchmarks/json/java/utf8_bytes_throughput.png) + +| Representation | Operation | fory-json ops/sec | jackson ops/sec | gson ops/sec | +| -------------- | ----------- | ----------------: | --------------: | -----------: | +| String | Serialize | 7,387,465 | 2,049,368 | 1,084,042 | +| String | Deserialize | 2,897,955 | 1,074,885 | 902,772 | +| UTF-8 bytes | Serialize | 10,375,498 | 1,868,614 | 1,037,211 | +| UTF-8 bytes | Deserialize | 3,077,158 | 1,268,397 | 933,079 | ## Related Java guides diff --git a/docs/json/object-mapping.md b/docs/json/object-mapping.md index 66375031d6..1563bc04d4 100644 --- a/docs/json/object-mapping.md +++ b/docs/json/object-mapping.md @@ -22,7 +22,7 @@ license: | ## Thread safety, reuse, and code generation `ForyJson` is immutable and thread-safe after `build()`. Reuse one instance instead of creating a -builder and runtime for every operation. Registered and annotation-selected `JsonValueCodec` +builder and `ForyJson` instance for every operation. Registered and annotation-selected `JsonValueCodec` instances and the `JsonTypeChecker` may be called concurrently and must also be thread-safe. Code generation and asynchronous compilation are enabled by default. Disabling code generation is @@ -126,7 +126,7 @@ Collection interfaces are reconstructed with standard mutable implementations, s `TreeMap`, `ConcurrentHashMap`, or `ConcurrentSkipListMap`. `ArrayBlockingQueue`, `Arrays.asList` results, JDK immutable collections, empty/singleton/unmodifiable wrappers, constructor-constrained implementations, and unlisted Guava immutable implementations cannot be reconstructed. Guava -support is optional and does not make Guava a required runtime dependency. +support is optional and does not make Guava a required application dependency. Non-finite float and double values use the quoted strings `"NaN"`, `"Infinity"`, and `"-Infinity"`. Use explicit `BigInteger` or `BigDecimal` targets when arbitrary precision must be @@ -213,7 +213,7 @@ size, only reusable writer storage retained after an operation. For class loading, type policy, nesting depth, graph-memory limits, and external input controls, see [Fory JSON Security](security.md). -Builder mutation after `build()` does not modify an existing `ForyJson` runtime. +Builder mutation after `build()` does not modify an existing `ForyJson` instance. On Android, runtime code generation and asynchronous compilation are disabled. In a GraalVM native image, runtime compilation is unavailable; configurations returned by a reachable diff --git a/docs/object-serialization/core-concepts.md b/docs/object-serialization/core-concepts.md index c122e6d450..bdb8e9b877 100644 --- a/docs/object-serialization/core-concepts.md +++ b/docs/object-serialization/core-concepts.md @@ -30,18 +30,18 @@ cycles. Serialization walks that graph from the root. Deserialization creates a encoded type and field data. This is different from serializing a row or a JSON document. Object serialization can preserve -runtime types and object identity so the reader can reconstruct application objects rather than +concrete object types and object identity so the reader can reconstruct application objects rather than only values. Use [Row Format](../row-format/index.md) for trusted analytical rows and [Fory JSON](../json/index.md) for JSON interchange. -## Runtime instances and registration +## Fory instances and registration A Fory instance owns its mode, schema behavior, reference settings, registered types, custom serializers, and read limits. Configure and register the instance before its first root serialization or deserialization operation, then reuse it. Registration is frozen after the first root operation so the same instance always resolves a type in the same way. -Thread-safety differs by runtime. Some runtimes provide a thread-safe wrapper or pool; others use +Thread-safety differs by Fory implementation. Some implementations provide a thread-safe wrapper or pool; others use one instance per thread or task. Follow the selected language guide instead of sharing an ordinary instance without checking its concurrency contract. @@ -52,13 +52,14 @@ extension types use a registered numeric ID or name. Type identity answers _whic model should read this value_; a field schema describes _what data that model contains_. A statically known field can use its declared type directly. A dynamic field also carries the -concrete runtime type needed for interfaces, abstract classes, trait objects, broad object types, +concrete type needed for interfaces, abstract classes, trait objects, broad object types, or heterogeneous values. Dynamic typing is more flexible but requires every possible concrete type to be registered and supported by the selected mode. In xlang mode, peers must coordinate the same portable type identity and mapping. Native mode may -use runtime-specific identities and types. See [Xlang Serialization](xlang.md) for the portable -rules and each language's Type Registration page for its exact API. +use implementation-specific identities and language-specific types. See +[Xlang Serialization](xlang.md) for the portable rules and each language's Type Registration page +for its exact API. ## Schemas and evolution @@ -90,7 +91,7 @@ than once or contains a cycle. Without reference tracking, repeated values may b objects and cycles may recurse until the operation fails. Leave reference tracking disabled for value-shaped, acyclic data when identity does not matter; it -adds per-object metadata and lookup work. Some runtimes combine a global setting with field-level +adds per-object metadata and lookup work. Some Fory implementations combine a global setting with field-level metadata, so use the language-specific References or Basic Serialization page for exact behavior. ## Polymorphism @@ -99,24 +100,25 @@ Polymorphism stores the concrete type of a value whose declared position is broa must know and accept that concrete type, and the type must be representable in the selected mode. Host-language inheritance alone does not create a portable contract. For cross-language data, -model only alternatives that have xlang mappings on every peer. For same-runtime data, native mode -may support additional runtime-specific class, trait, or hook behavior. +model only alternatives that have xlang mappings on every peer. For data within one Fory +implementation family, native mode may support additional language-specific class, trait, or hook +behavior. ## Custom serializers Use a custom serializer when a type needs a representation that built-in schema inference cannot provide. Registration connects the custom serializer to the application type. A custom serializer must follow the selected mode's rules: xlang serializers need a portable representation, while -native serializers may use runtime-specific data and hooks. +native serializers may use language-specific data and hooks. Prefer built-in serializers and generated models when they already describe the type. They keep schema evolution, reference handling, and cross-language behavior easier to reason about. ## Continue with a mode -- [Xlang Serialization](xlang.md) is the default and is required when different language runtimes - exchange bytes. -- [Native Serialization](native.md) is for supported same-runtime use cases that need native types - or behavior. +- [Xlang Serialization](xlang.md) is the default and is required when peers use different Fory + implementation families or need a portable contract. +- [Native Serialization](native.md) is for supported use cases within one Fory implementation + family that need native types or behavior. - Choose a language section after selecting a mode to find installation, API, configuration, registration, platform, security, and troubleshooting guidance. diff --git a/docs/object-serialization/cpp/basic-serialization.md b/docs/object-serialization/cpp/basic-serialization.md index 275ad53ed4..ae71428a9d 100644 --- a/docs/object-serialization/cpp/basic-serialization.md +++ b/docs/object-serialization/cpp/basic-serialization.md @@ -357,7 +357,7 @@ fory.register_struct(2); ## Cross-Language Interoperability -The default xlang format is shared by all Fory runtimes. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. +The default xlang format is shared by all supported Fory implementations. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. This page explains how to use Fory xlang serialization between C++ and other languages. diff --git a/docs/object-serialization/cpp/configuration.md b/docs/object-serialization/cpp/configuration.md index 78c77939d2..42d066000c 100644 --- a/docs/object-serialization/cpp/configuration.md +++ b/docs/object-serialization/cpp/configuration.md @@ -108,7 +108,7 @@ auto fory = Fory::builder() The default limit is a fixed `128 MiB` for byte-array, `Buffer`, and stream roots. Positive values override the default. Explicit non-positive values are -rejected when the runtime is created. +rejected when the Fory instance is created. This budget is an approximate lower-bound estimate for materialized graph owners, mainly collections, maps, arrays, structs, and objects. It is not an diff --git a/docs/object-serialization/cpp/polymorphism.md b/docs/object-serialization/cpp/polymorphism.md index 383ba7c36d..553214a674 100644 --- a/docs/object-serialization/cpp/polymorphism.md +++ b/docs/object-serialization/cpp/polymorphism.md @@ -206,7 +206,7 @@ static_cast(container.pet.get())->breed = "Beagle"; auto bytes = fory.serialize(container).value(); auto decoded = fory.deserialize(bytes).value(); -// Runtime type preserved +// Dynamic type preserved auto* dog = dynamic_cast(decoded.pet.get()); assert(dog != nullptr); assert(dog->breed == "Beagle"); diff --git a/docs/object-serialization/cpp/security.md b/docs/object-serialization/cpp/security.md index fe86e37d2d..860505ee98 100644 --- a/docs/object-serialization/cpp/security.md +++ b/docs/object-serialization/cpp/security.md @@ -33,7 +33,7 @@ Before deserialization: first root operation. - Validate the deserialized value against application authorization and domain rules before use. -## Runtime safeguards +## Built-in safeguards Security-related configuration: @@ -51,7 +51,7 @@ Security-related configuration: Add negative tests for the boundary as well as normal round trips. Verify that the configured reader rejects unexpected application types, excessive nesting, resource-limit violations, and malformed -input. After a failed read, verify that a valid root can still be read with the reusable runtime. +input. After a failed read, verify that a valid root can still be read with the same Fory instance. See [Configuration](configuration.md) for the complete option reference and -[Type Registration](type-registration.md) for the runtime's registration API. +[Type Registration](type-registration.md) for the Fory registration API. diff --git a/docs/object-serialization/csharp/basic-serialization.md b/docs/object-serialization/csharp/basic-serialization.md index 7c77560a7d..af40c1a309 100644 --- a/docs/object-serialization/csharp/basic-serialization.md +++ b/docs/object-serialization/csharp/basic-serialization.md @@ -161,7 +161,7 @@ fory.Serialize(dynamicWriter, value); ## Cross-Language Interoperability -The default xlang format is shared by all Fory runtimes. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. +The default xlang format is shared by all Fory implementations. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. Apache Fory™ C# supports xlang serialization with other Fory implementations. diff --git a/docs/object-serialization/csharp/configuration.md b/docs/object-serialization/csharp/configuration.md index 5bac8df215..7ac807affc 100644 --- a/docs/object-serialization/csharp/configuration.md +++ b/docs/object-serialization/csharp/configuration.md @@ -112,7 +112,7 @@ Fory fory = Fory.Builder() ``` The default limit is a fixed `128 MiB` for all root input forms. A positive value overrides the -default. Explicit non-positive values are rejected when the runtime is created. Skipped leaf values +default. Explicit non-positive values are rejected when the Fory instance is created. Skipped leaf values are still gated by remaining input bytes: if the unread input does not contain enough bytes, Fory will not read or create that leaf value. diff --git a/docs/object-serialization/csharp/external-types.md b/docs/object-serialization/csharp/external-types.md index 0b1e18fd1a..b14b7aeb0e 100644 --- a/docs/object-serialization/csharp/external-types.md +++ b/docs/object-serialization/csharp/external-types.md @@ -131,7 +131,7 @@ private mapping is an application-owned package ABI declaration. Pin and test the package version together with the declaration. If a mapped private field changes, the generated exact accessor fails with the CLR's missing-field error; Fory does not fall back to reflection or another member. An ignored private -field has no runtime accessor, so validate that storage declaration against the +field has no generated accessor, so validate that storage declaration against the pinned package build. External struct targets support visible field and property mappings only. @@ -306,7 +306,7 @@ List decoded = ``` External children are supported through the concrete carrier types already -supported by the C# runtime: +supported by Fory C#: - `Nullable` for external structs and one-dimensional `T[]`; - `List`, `LinkedList`, `Queue`, and `Stack`; diff --git a/docs/object-serialization/csharp/schema-metadata.md b/docs/object-serialization/csharp/schema-metadata.md index 99f9cb3a62..d9858982e5 100644 --- a/docs/object-serialization/csharp/schema-metadata.md +++ b/docs/object-serialization/csharp/schema-metadata.md @@ -29,7 +29,7 @@ External-type serialization puts `Target` on a local abstract serializer declaration. Its properties own the field names, IDs, schema descriptors, and nullability. A standalone declaration also owns its `Evolving` setting. An external `BaseOnly` declaration cannot set `Evolving`; each concrete -descendant owns that setting. The target supplies the runtime values and +descendant owns that setting. The target supplies values of the target type and directly accessed members. ```csharp diff --git a/docs/object-serialization/csharp/security.md b/docs/object-serialization/csharp/security.md index 06416a73e0..58c33374be 100644 --- a/docs/object-serialization/csharp/security.md +++ b/docs/object-serialization/csharp/security.md @@ -33,7 +33,7 @@ Before deserialization: first root operation. - Validate the deserialized value against application authorization and domain rules before use. -## Runtime safeguards +## Built-in safeguards Security-related configuration: @@ -50,7 +50,7 @@ Security-related configuration: Add negative tests for the boundary as well as normal round trips. Verify that the configured reader rejects unexpected application types, excessive nesting, resource-limit violations, and malformed -input. After a failed read, verify that a valid root can still be read with the reusable runtime. +input. After a failed read, verify that a valid root can still be read with the same Fory instance. See [Configuration](configuration.md) for the complete option reference and -[Type Registration](type-registration.md) for the runtime's registration API. +[Type Registration](type-registration.md) for the Fory registration API. diff --git a/docs/object-serialization/dart/basic-serialization.md b/docs/object-serialization/dart/basic-serialization.md index 0b28adb02b..4ada0c62c4 100644 --- a/docs/object-serialization/dart/basic-serialization.md +++ b/docs/object-serialization/dart/basic-serialization.md @@ -140,7 +140,7 @@ If you skip registration, deserialization fails with `Type ... is not registered ## Cross-Language Interoperability -The default xlang format is shared by all Fory runtimes. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. +The default xlang format is shared by all Fory implementations. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. Apache Fory™ Dart serializes to the same binary format as the Java, Go, C#, Python, Rust, and Swift Fory implementations. You can write a message in Dart and read it in Java — or any other direction — without any conversion layer. diff --git a/docs/object-serialization/dart/configuration.md b/docs/object-serialization/dart/configuration.md index 7094e9b4a9..e310843651 100644 --- a/docs/object-serialization/dart/configuration.md +++ b/docs/object-serialization/dart/configuration.md @@ -126,7 +126,7 @@ collection/map/struct gate: final fory = Fory(maxGraphMemoryBytes: 256 * 1024 * 1024); ``` -Explicit non-positive values are rejected when the runtime is created. +Explicit non-positive values are rejected when the Fory instance is created. ### `maxUnbackedContainerItems` diff --git a/docs/object-serialization/dart/external-types.md b/docs/object-serialization/dart/external-types.md index 0141164b4e..2ec2796172 100644 --- a/docs/object-serialization/dart/external-types.md +++ b/docs/object-serialization/dart/external-types.md @@ -226,7 +226,7 @@ Register every concrete external type that can appear dynamically. Non-empty root lists, sets, and maps decode their elements, keys, and values as the registered external targets. Dart root collections retain their existing -runtime shapes, so read a root collection as `Object?` and cast its outer +untyped outer shapes, so read a root collection as `Object?` and cast its outer carrier: ```dart diff --git a/docs/object-serialization/dart/schema-evolution.md b/docs/object-serialization/dart/schema-evolution.md index 6f290413a1..560bd7b684 100644 --- a/docs/object-serialization/dart/schema-evolution.md +++ b/docs/object-serialization/dart/schema-evolution.md @@ -124,7 +124,7 @@ must change together because the resulting field list is different. A parent annotation does not propagate this setting to children. This option changes generated field selection only. It does not change the -runtime reference protocol or add a compatibility reader. +reference protocol or add a compatibility reader. ## Related Topics diff --git a/docs/object-serialization/dart/security.md b/docs/object-serialization/dart/security.md index 4367148291..a3f5d4ca85 100644 --- a/docs/object-serialization/dart/security.md +++ b/docs/object-serialization/dart/security.md @@ -33,7 +33,7 @@ Before deserialization: first root operation. - Validate the deserialized value against application authorization and domain rules before use. -## Runtime safeguards +## Built-in safeguards Security-related configuration: @@ -50,7 +50,7 @@ Security-related configuration: Add negative tests for the boundary as well as normal round trips. Verify that the configured reader rejects unexpected application types, excessive nesting, resource-limit violations, and malformed -input. After a failed read, verify that a valid root can still be read with the reusable runtime. +input. After a failed read, verify that a valid root can still be read with the same Fory instance. See [Configuration](configuration.md) for the complete option reference and -[Type Registration](type-registration.md) for the runtime's registration API. +[Type Registration](type-registration.md) for the Fory registration API. diff --git a/docs/object-serialization/dart/type-registration.md b/docs/object-serialization/dart/type-registration.md index 2364c81bd6..574039f98c 100644 --- a/docs/object-serialization/dart/type-registration.md +++ b/docs/object-serialization/dart/type-registration.md @@ -67,11 +67,11 @@ UserModelsForyModule.register(fory, User, id: 100); For an ordinary inherited type, register the concrete annotated child. Its generated serializer already owns the complete flattened child schema; Fory -does not require runtime registration of a superclass or mixin merely because +does not require separate registration of a superclass or mixin merely because it contributes fields. Register an independently annotated concrete parent only when values whose -runtime type is that parent are also serialized. A provider-only +actual type is exactly that parent are also serialized. A provider-only `@ForyStruct(exposePrivateFields: true)` boundary supplies generated field access and has no registration entry of its own. See [Struct Inheritance](inheritance.md) for boundary and child-schema options. diff --git a/docs/object-serialization/go/basic-serialization.md b/docs/object-serialization/go/basic-serialization.md index e5b19b3fc5..8dca339ffb 100644 --- a/docs/object-serialization/go/basic-serialization.md +++ b/docs/object-serialization/go/basic-serialization.md @@ -403,7 +403,7 @@ func main() { ## Cross-Language Interoperability -The default xlang format is shared by all Fory runtimes. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. +The default xlang format is shared by all Fory implementations. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. Fory Go enables seamless data exchange with Java, Python, C++, Rust, JavaScript/TypeScript, C#, Swift, Dart, Scala, and Kotlin. This guide covers diff --git a/docs/object-serialization/go/configuration.md b/docs/object-serialization/go/configuration.md index e3de7416ed..8f59db06e2 100644 --- a/docs/object-serialization/go/configuration.md +++ b/docs/object-serialization/go/configuration.md @@ -144,7 +144,7 @@ leaf values such as strings, binary data, primitive scalars, and dense primitive process memory can be higher than this value. The default limit is a fixed `128 MiB` for all root input forms. A positive value overrides the -default. Explicit non-positive values are rejected when the runtime is created. Graph memory +default. Explicit non-positive values are rejected when the Fory instance is created. Graph memory reservation complements byte-availability checks; it does not replace them. Skipped leaf values are still gated by remaining input bytes: if the unread input does not contain enough bytes, Fory will not read or create that leaf value. @@ -214,7 +214,7 @@ xlang := fory.New(fory.WithXlang(true)) - Go-native serialization mode - Supports more Go-native type behavior -- Not compatible with other language implementations +- Not wire-compatible with other Fory implementation families ## Thread Safety diff --git a/docs/object-serialization/go/security.md b/docs/object-serialization/go/security.md index 916643e3e3..0ad71c5513 100644 --- a/docs/object-serialization/go/security.md +++ b/docs/object-serialization/go/security.md @@ -33,7 +33,7 @@ Before deserialization: first root operation. - Validate the deserialized value against application authorization and domain rules before use. -## Runtime safeguards +## Built-in safeguards Security-related configuration: @@ -47,7 +47,7 @@ Security-related configuration: Add negative tests for the boundary as well as normal round trips. Verify that the configured reader rejects unexpected application types, excessive nesting, resource-limit violations, and malformed -input. After a failed read, verify that a valid root can still be read with the reusable runtime. +input. After a failed read, verify that a valid root can still be read with the same Fory instance. See [Configuration](configuration.md) for the complete option reference and -[Type Registration](type-registration.md) for the runtime's registration API. +[Type Registration](type-registration.md) for the Fory registration API. diff --git a/docs/object-serialization/index.md b/docs/object-serialization/index.md index 02eeae901e..0fbf24c06f 100644 --- a/docs/object-serialization/index.md +++ b/docs/object-serialization/index.md @@ -24,10 +24,10 @@ collections, polymorphic values, and optional shared references. ## Choose a mode -| Mode | Use it when | Start here | -| --------------- | ---------------------------------------------------- | --------------------------------- | -| Xlang (default) | Bytes cross runtime boundaries | [Xlang Serialization](xlang.md) | -| Native | Every writer and reader uses the same runtime family | [Native serialization](native.md) | +| Mode | Use it when | Start here | +| --------------- | ----------------------------------------------------------- | --------------------------------- | +| Xlang (default) | Bytes cross language boundaries | [Xlang Serialization](xlang.md) | +| Native | Every writer and reader uses one Fory implementation family | [Native serialization](native.md) | Xlang and native are the only object-serialization modes. Row Format is a random-access analytical representation, and Fory JSON is a Java JSON codec; use the @@ -35,32 +35,33 @@ representation, and Fory JSON is a Java JSON codec; use the ## Read the concepts and modes -Read these pages before choosing a runtime API: +Read these pages before choosing the Fory API for a language: 1. [Core Concepts](core-concepts.md) explains object graphs, types, schemas, references, polymorphism, and schema evolution across both modes. 2. [Xlang Serialization](xlang.md) explains the portable format used by default and the rules that - different language runtimes must share. -3. [Native Serialization](native.md) explains when a same-runtime native format is appropriate. + Fory implementations in different languages must share. +3. [Native Serialization](native.md) explains when an implementation-specific native format is + appropriate. -## Browse by runtime +## Browse by language -Choose a runtime to find its installation route, lifecycle, exact APIs, configuration, type +Choose a language to find its installation route, lifecycle, exact APIs, configuration, type registration, schema behavior, extensions, platforms, and troubleshooting: -| Runtime | Modes | Documentation | -| --------------------- | -------------------- | ------------------------------------------------------ | -| Java | xlang and native | [Java runtime](./java/index.md) | -| Python | xlang and native | [Python runtime](./python/index.md) | -| C++ | xlang and native | [C++ runtime](./cpp/index.md) | -| Go | xlang and native | [Go runtime](./go/index.md) | -| Rust | xlang and native | [Rust runtime](./rust/index.md) | -| JavaScript/TypeScript | xlang | [JavaScript/TypeScript runtime](./javascript/index.md) | -| C# | xlang | [C# runtime](./csharp/index.md) | -| Swift | xlang | [Swift runtime](./swift/index.md) | -| Dart | xlang | [Dart runtime](./dart/index.md) | -| Scala | xlang and JVM native | [Scala runtime](./scala/index.md) | -| Kotlin | xlang and JVM native | [Kotlin runtime](./kotlin/index.md) | +| Language | Modes | Documentation | +| --------------------- | -------------------- | ---------------------------------------------------- | +| Java | xlang and native | [Java guide](./java/index.md) | +| Python | xlang and native | [Python guide](./python/index.md) | +| C++ | xlang and native | [C++ guide](./cpp/index.md) | +| Go | xlang and native | [Go guide](./go/index.md) | +| Rust | xlang and native | [Rust guide](./rust/index.md) | +| JavaScript/TypeScript | xlang | [JavaScript/TypeScript guide](./javascript/index.md) | +| C# | xlang | [C# guide](./csharp/index.md) | +| Swift | xlang | [Swift guide](./swift/index.md) | +| Dart | xlang | [Dart guide](./dart/index.md) | +| Scala | xlang and JVM native | [Scala guide](./scala/index.md) | +| Kotlin | xlang and JVM native | [Kotlin guide](./kotlin/index.md) | ## Specifications diff --git a/docs/object-serialization/java/android.md b/docs/object-serialization/java/android.md index 34fd3ea105..817c99d15f 100644 --- a/docs/object-serialization/java/android.md +++ b/docs/object-serialization/java/android.md @@ -19,7 +19,7 @@ license: | limitations under the License. --- -## Android Runtime +## Android Support Fory Java supports Android 8.0+ (API level 26+) through the regular `fory-core` artifact. No separate Android artifact is required for core object serialization. diff --git a/docs/object-serialization/java/basic-serialization.md b/docs/object-serialization/java/basic-serialization.md index 70fb3ea7dc..464145215c 100644 --- a/docs/object-serialization/java/basic-serialization.md +++ b/docs/object-serialization/java/basic-serialization.md @@ -125,7 +125,7 @@ object copy, and native-mode zero-copy buffers. See [Native Serialization](nativ ## Cross-Language Interoperability -The default xlang format is shared by all Fory runtimes. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. +The default xlang format is shared by all supported Fory implementations. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. Apache Fory™ xlang serialization is the Java wire mode for payloads that must be read by Python, Rust, Go, JavaScript/TypeScript, C++, C#, Swift, Dart, Scala, Kotlin, or another non-Java Fory implementation. Java defaults to diff --git a/docs/object-serialization/java/index.md b/docs/object-serialization/java/index.md index 2d5add91f8..15fadb9c40 100644 --- a/docs/object-serialization/java/index.md +++ b/docs/object-serialization/java/index.md @@ -20,9 +20,9 @@ license: | --- Apache Fory Java provides high-performance binary object serialization. Use xlang mode for payloads -shared with other supported runtimes and native mode for Java/JVM-only object graphs. +shared across Fory implementation families and native mode for JVM-family object graphs. -This runtime guide is scoped to Binary Object Serialization. For other Java capabilities, use +This Java guide is scoped to Binary Object Serialization. For other Java capabilities, use [Row Format](../../row-format/java.md), [Fory JSON](../../json/index.md), [Fory IDL and compiler](../../compiler/index.md), or [Fory gRPC](../../grpc/java.md). @@ -76,8 +76,10 @@ implementation("org.apache.fory:fory-core:1.5.0") #### JDK 25 and Later -On JDK 25 and later, open `java.lang.invoke` to Fory. Use `ALL-UNNAMED` when Fory is on -the classpath: +On JDK 25 and later, opening `java.lang.invoke` to Fory core is not required, but is recommended. It avoids +the current-JDK Unsafe fallback and is required when Unsafe access is disabled or unavailable, +including with `--sun-misc-unsafe-memory-access=deny`. Use `ALL-UNNAMED` when Fory is on the +classpath: ```bash --add-opens=java.base/java.lang.invoke=ALL-UNNAMED diff --git a/docs/object-serialization/java/schema-evolution.md b/docs/object-serialization/java/schema-evolution.md index 9a2796306e..044768fb54 100644 --- a/docs/object-serialization/java/schema-evolution.md +++ b/docs/object-serialization/java/schema-evolution.md @@ -27,7 +27,7 @@ In many systems, the schema of a class used for serialization may change over ti ### Default Mode -Fory defaults to compatible mode in both Java native mode (`xlang=false`) and xlang mode. This default is safer for independently deployed services because writer and reader schemas can diverge during rolling upgrades or across language implementations. +Fory defaults to compatible mode in both Java native mode (`xlang=false`) and xlang mode. This default is safer for independently deployed services because writer and reader schemas can diverge during rolling upgrades or across Fory implementations in different languages. For payloads whose reader and writer schemas never differ, see [Same-Schema Optimization](#same-schema-optimization). diff --git a/docs/object-serialization/java/security.md b/docs/object-serialization/java/security.md index 780d39b2d2..77f6ac4350 100644 --- a/docs/object-serialization/java/security.md +++ b/docs/object-serialization/java/security.md @@ -33,7 +33,7 @@ Before deserialization: first root operation. - Validate the deserialized value against application authorization and domain rules before use. -## Runtime safeguards +## Built-in safeguards Keep class registration enabled for production and any untrusted payload source: @@ -77,7 +77,7 @@ allow list when dynamic class loading is required. Add negative tests for the boundary as well as normal round trips. Verify that the configured reader rejects unexpected application types, excessive nesting, resource-limit violations, and malformed -input. After a failed read, verify that a valid root can still be read with the reusable runtime. +input. After a failed read, verify that a valid root can still be read with the same Fory instance. See [Configuration](configuration.md) for the complete option reference and -[Type Registration](type-registration.md) for the runtime's registration API. +[Type Registration](type-registration.md) for the Fory registration API. diff --git a/docs/object-serialization/java/static-generated-serializers.md b/docs/object-serialization/java/static-generated-serializers.md index 14f7546263..4eea62dbf1 100644 --- a/docs/object-serialization/java/static-generated-serializers.md +++ b/docs/object-serialization/java/static-generated-serializers.md @@ -104,7 +104,7 @@ public class DebugOrder { } ``` -## Runtime Use +## Serializer Selection Fory uses static generated serializers when they are available on: diff --git a/docs/object-serialization/java/troubleshooting.md b/docs/object-serialization/java/troubleshooting.md index 8d68b68b0c..d70a027552 100644 --- a/docs/object-serialization/java/troubleshooting.md +++ b/docs/object-serialization/java/troubleshooting.md @@ -185,8 +185,10 @@ fory.registerSerializer(MyClass.class, new MyClassSerializer(fory.getTypeResolve ### JDK25+ access errors -On JDK25+, if an error names `java.base/java.lang.invoke`, open `java.lang.invoke` to Fory. Use -`ALL-UNNAMED` when Fory is on the classpath: +On JDK25+, opening `java.lang.invoke` to Fory core is not required, but is recommended. Add the opening if +an error names `java.base/java.lang.invoke`, or when Unsafe access is disabled or unavailable, +including with `--sun-misc-unsafe-memory-access=deny`. Use `ALL-UNNAMED` when Fory is on the +classpath: ```bash --add-opens=java.base/java.lang.invoke=ALL-UNNAMED diff --git a/docs/object-serialization/javascript/basic-serialization.md b/docs/object-serialization/javascript/basic-serialization.md index ce14adb1ce..28752265cc 100644 --- a/docs/object-serialization/javascript/basic-serialization.md +++ b/docs/object-serialization/javascript/basic-serialization.md @@ -239,7 +239,7 @@ This is useful when debugging schema behavior, field ordering, or generated fast ## Cross-Language Interoperability -The default xlang format is shared by all Fory runtimes. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. +The default xlang format is shared by all Fory implementations. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. Fory JavaScript serializes to the same binary format as the Java, Python, C++, Go, Rust, C#, Swift, Dart, Scala, and Kotlin Fory implementations. You can write a diff --git a/docs/object-serialization/javascript/configuration.md b/docs/object-serialization/javascript/configuration.md index c73194882e..51c0544689 100644 --- a/docs/object-serialization/javascript/configuration.md +++ b/docs/object-serialization/javascript/configuration.md @@ -113,7 +113,7 @@ const fory = new Fory({ }); ``` -Explicit non-positive values are rejected when the runtime is created. +Explicit non-positive values are rejected when the Fory instance is created. String, binary, and dedicated dense primitive array payloads keep their normal byte-size checks and do not consume this graph budget. Raise the limit only for diff --git a/docs/object-serialization/javascript/security.md b/docs/object-serialization/javascript/security.md index 6a01ac5b73..8b0f959030 100644 --- a/docs/object-serialization/javascript/security.md +++ b/docs/object-serialization/javascript/security.md @@ -33,7 +33,7 @@ Before deserialization: first root operation. - Validate the deserialized value against application authorization and domain rules before use. -## Runtime safeguards +## Built-in safeguards Security-related configuration: @@ -54,7 +54,7 @@ Security-related configuration: Add negative tests for the boundary as well as normal round trips. Verify that the configured reader rejects unexpected application types, excessive nesting, resource-limit violations, and malformed -input. After a failed read, verify that a valid root can still be read with the reusable runtime. +input. After a failed read, verify that a valid root can still be read with the same Fory instance. See [Configuration](configuration.md) for the complete option reference and -[Type Registration](type-registration.md) for the runtime's registration API. +[Type Registration](type-registration.md) for the Fory registration API. diff --git a/docs/object-serialization/kotlin/basic-serialization.md b/docs/object-serialization/kotlin/basic-serialization.md index 0fdbfb3c04..7b88988f01 100644 --- a/docs/object-serialization/kotlin/basic-serialization.md +++ b/docs/object-serialization/kotlin/basic-serialization.md @@ -26,7 +26,7 @@ Xlang is the default serialization mode for Fory Kotlin. This page covers the ba The following sections cover model generation, registration, and cross-language round trips in the default xlang mode. Kotlin xlang serialization uses the JVM Fory implementation through `ForyKotlin`. Use it when -Kotlin payloads must be read by another supported Fory runtime. Register portable model types with +Kotlin payloads must be read by another supported Fory implementation. Register portable model types with the same identity and field schema on every peer. Kotlin data classes, enums, and sealed-class models use the Kotlin integration and generated diff --git a/docs/object-serialization/kotlin/index.md b/docs/object-serialization/kotlin/index.md index 5b5910fff2..77dda3e8c9 100644 --- a/docs/object-serialization/kotlin/index.md +++ b/docs/object-serialization/kotlin/index.md @@ -65,8 +65,10 @@ implementation("org.apache.fory:fory-kotlin:1.5.0") ### JDK25+ -Kotlin uses the Fory Java core when running. On JDK25+, open `java.lang.invoke` -to Fory. Use `ALL-UNNAMED` when Fory is on the classpath: +Kotlin uses the Fory Java core when running. On JDK25+, opening `java.lang.invoke` to Fory core is +not required, but is recommended. It avoids the current-JDK Unsafe fallback and is required when Unsafe +access is disabled or unavailable, including with `--sun-misc-unsafe-memory-access=deny`. Use +`ALL-UNNAMED` when Fory is on the classpath: ```bash --add-opens=java.base/java.lang.invoke=ALL-UNNAMED diff --git a/docs/object-serialization/kotlin/native.md b/docs/object-serialization/kotlin/native.md index 99a88b9670..58b0415cdd 100644 --- a/docs/object-serialization/kotlin/native.md +++ b/docs/object-serialization/kotlin/native.md @@ -190,7 +190,7 @@ The following types work with the default Fory Java implementation: Use `ForyKotlin.builder()` for Kotlin-specific types such as unsigned values, ranges, and `Duration`. -Use native mode for Kotlin/JVM-only traffic that needs Kotlin data classes, -nullable types, ranges, unsigned values, or Kotlin collections on the JVM runtime -path. Choose registration and thread-safety settings for the application in +Use native mode for Kotlin/JVM-only traffic with Kotlin data classes, nullable +types, ranges, unsigned values, or Kotlin collections. Choose registration and +thread-safety settings for the application in [Kotlin Configuration](configuration.md). diff --git a/docs/object-serialization/kotlin/security.md b/docs/object-serialization/kotlin/security.md index 56bbafd556..84340916c5 100644 --- a/docs/object-serialization/kotlin/security.md +++ b/docs/object-serialization/kotlin/security.md @@ -33,7 +33,7 @@ Before deserialization: first root operation. - Validate the deserialized value against application authorization and domain rules before use. -## Runtime safeguards +## Built-in safeguards Kotlin uses the Java configuration surface. Keep class registration enabled for production and any untrusted payload source: @@ -68,7 +68,7 @@ Security-related configuration: Add negative tests for the boundary as well as normal round trips. Verify that the configured reader rejects unexpected application types, excessive nesting, resource-limit violations, and malformed -input. After a failed read, verify that a valid root can still be read with the reusable runtime. +input. After a failed read, verify that a valid root can still be read with the same Fory instance. See [Configuration](configuration.md) for the Kotlin option reference and [Java Type Registration](../java/type-registration.md) for the underlying registration API. diff --git a/docs/object-serialization/native.md b/docs/object-serialization/native.md index d5bf9a87dc..d6a3e3d03d 100644 --- a/docs/object-serialization/native.md +++ b/docs/object-serialization/native.md @@ -19,18 +19,152 @@ license: | limitations under the License. --- -Native serialization uses a binding-specific wire format and the owning runtime's native type -system. It is not one shared cross-language protocol. +Native serialization uses an implementation-specific wire format and the host language's native +type system. Choose it when every writer and reader uses the same Fory implementation family and +the payload should preserve language-specific types or behavior. Native payloads from different +implementation families are not interchangeable. -## When to use native mode +Use [xlang serialization](xlang.md) whenever a peer with a different native wire format must read +the bytes. Xlang uses a shared type system and wire format; native mode deliberately stays closer to +the implementation family's native object model. -Use native mode for same-runtime traffic that needs language-specific object shapes, migration from -a host serializer, or a smaller/faster format without xlang type-mapping constraints. Use -[xlang mode](xlang.md) whenever a different runtime must read the bytes. +Native and xlang type support overlap. A type listed on this page is not necessarily exclusive to +native mode; many language-native carriers also work in xlang when they have a portable mapping. +Choose the mode from the data boundary and required wire contract first, then check the language's +type mapping for the specific model. -## Supported runtime families +## When To Use Native Mode -- [Java](java/native.md), including the JVM path used by Scala and Kotlin +Native mode is the right choice when: + +- every producer and consumer uses one Fory implementation family; +- the object graph contains language-specific types or behavior outside the portable xlang type + mapping; +- an application is moving from an existing same-language serializer and should keep its current + object model instead of introducing a cross-language schema; or +- stored or transported data stays within one implementation family rather than a contract shared + across implementation families. + +Use xlang instead when peers use different Fory implementation families, when the contract must +remain language-independent, or when portability is more important than the full native object +surface. + +| Scenario | Recommended mode | +| ------------------------------------------------------------- | ---------------- | +| One implementation family with language-specific types | Native | +| Replacement for an existing same-language object serializer | Native | +| Data exchanged across Fory implementation families | Xlang | +| A long-lived contract intended to remain language-independent | Xlang | + +## Java + +Choose [Java native serialization](java/native.md) for Java/JVM-only payloads that need a broader +Java object surface than the portable xlang mapping. This includes ordinary Java objects, records, +enums, primitive and object arrays, common JDK collections and wrappers, interfaces, inheritance, +shared references, and circular object graphs. + +Java native mode also supports classes that use JDK serialization hooks: + +- `writeObject` and `readObject`; +- `writeReplace` and `readResolve`; +- `readObjectNoData`; and +- `Externalizable`. + +Fory honors these hooks while writing Fory native bytes; it does not emit Java +`ObjectOutputStream` bytes. See [JDK Custom Serialization](java/jdk-serialization.md) for the exact +semantics. + +Use Java native mode when replacing Java-only use of Kryo, FST, Hessian, or JDK serialization and +the existing Java object model should remain the serialization model. + +## Python + +Choose [Python native serialization](python/native.md) for Python-only payloads that need Python +objects beyond the portable xlang surface. Native mode supports classes, global and local +functions, lambdas, closures, instance methods, class methods, static methods, shared references, +and circular object graphs. + +It also supports Python object construction and state hooks, including: + +- `__getstate__` and `__setstate__`; +- `__getnewargs__` and `__getnewargs_ex__`; and +- `__reduce__` and `__reduce_ex__`. + +Use it when replacing Pickle or cloudpickle for a Python-only object graph. It is also an option for +replacing a Python-only MessagePack boundary when both endpoints move to Fory and the application +wants to serialize Python objects directly. If MessagePack is currently used as a language-neutral +exchange format, use xlang instead. + +See [Functions, Classes, and Methods](python/functions-classes-methods.md) and +[Serialization Hooks](python/serialization-hooks.md) for the supported Python object shapes and +reconstruction behavior. + +## Rust + +Choose [Rust native serialization](rust/native.md) when every endpoint is Rust and the payload +should use the Rust-specific wire format. This choice does not mean common Rust containers, +`Rc`, `Arc`, trait objects, or `dyn Any` are unavailable in xlang. Those carriers can also +participate in xlang when their selected concrete types have portable mappings. Use the +[Xlang Type Mapping](../specification/xlang_type_mapping.md) and the Rust language guide to check the +exact model. + +One native-specific shape is a data-carrying, struct-style enum whose variants contain multiple +fields directly. In native mode, a `#[derive(ForyUnion)]` enum can mix unit variants, tuple variants +with one or more fields, and named variants with one or more fields: + +```rust +use fory::ForyUnion; + +#[derive(ForyUnion)] +enum Command { + #[fory(default)] + Idle, + Move(i32, i32), + Create { id: u128, label: String }, +} +``` + +An xlang UNION alternative carries at most one declared payload value. Multiple logical fields must +be wrapped in an explicitly declared struct for xlang, while Rust native mode can encode the tuple +or named fields directly. See [Rust Enum Support](rust/schema-evolution.md#enum-support) and +[External-Type Serialization](rust/external-types.md#native-struct-style-enums) for local and +third-party enum shapes. + +## C++ + +Choose [C++ native serialization](cpp/native.md) when every endpoint is C++ and the data model +should use the C++-specific wire format. Standard containers, structs and classes, +`std::optional`, `std::variant`, tuple-like values, smart pointers, and supported scalar carriers +are not categorically native-only; they can also work in xlang when the corresponding portable +mapping exists. + +Choose native mode because the boundary is C++-only or because the particular model needs a +C++-specific representation, not merely because it uses a C++ standard-library type. Use +[Supported Types](cpp/supported-types.md) for the exact native and xlang mappings. + +## Migrating From Another Serializer + +Native mode is a replacement serialization path, not a decoder for another library's wire format. +Kryo, FST, Hessian, JDK serialization, Pickle, cloudpickle, and MessagePack bytes do not become Fory +native bytes automatically. + +Move writers and readers to the corresponding Fory implementation family together. If existing +stored data must remain readable during migration, keep the previous decoder at that boundary and +reserialize values with Fory as they are migrated. Do not use native mode for a boundary that still +has readers using a different native wire format. + +## Enable Native Mode + +| Language | Native-mode configuration | +| -------- | ----------------------------------------- | +| Java | `Fory.builder().withXlang(false).build()` | +| Python | `pyfory.Fory(xlang=False)` | +| C++ | `Fory::builder().xlang(false).build()` | +| Rust | `Fory::builder().xlang(false).build()` | + +## Language Guides + +- [Java](java/native.md) - [Python](python/native.md) - [C++](cpp/native.md) - [Go](go/native.md) @@ -38,5 +172,5 @@ a host serializer, or a smaller/faster format without xlang type-mapping constra - [Scala](scala/native.md) - [Kotlin](kotlin/native.md) -Each runtime page owns its exact object model, schema rules, configuration, extension APIs, and -diagnostics. Native payloads from different runtime families are not interchangeable. +Each language guide owns its exact supported types, configuration, schema behavior, extension APIs, +and diagnostics. diff --git a/docs/object-serialization/python/basic-serialization.md b/docs/object-serialization/python/basic-serialization.md index 489bc77929..b7245315d6 100644 --- a/docs/object-serialization/python/basic-serialization.md +++ b/docs/object-serialization/python/basic-serialization.md @@ -106,7 +106,7 @@ for obj in objects: ## Cross-Language Interoperability -The default xlang format is shared by all Fory runtimes. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. +The default xlang format is shared by all supported Fory implementations. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. `pyfory` supports xlang object graph serialization, allowing you to serialize data in Python and deserialize it in Java, C++, Go, Rust, diff --git a/docs/object-serialization/python/schema-metadata.md b/docs/object-serialization/python/schema-metadata.md index 913cafb4f8..e7359c96a9 100644 --- a/docs/object-serialization/python/schema-metadata.md +++ b/docs/object-serialization/python/schema-metadata.md @@ -320,7 +320,7 @@ class Counters: ``` For `values`, map keys are written as fixed-width int32 values and each nested list element is -written as tagged int64. Runtime type inference is used only for dynamic or unknown container +written as tagged int64. Value-based type inference is used only for dynamic or unknown container schemas. In compatible mode, readers consume field bytes using the remote schema metadata. Python assigns the diff --git a/docs/object-serialization/python/security.md b/docs/object-serialization/python/security.md index db9e96c980..df3c5cba6b 100644 --- a/docs/object-serialization/python/security.md +++ b/docs/object-serialization/python/security.md @@ -33,7 +33,7 @@ Before deserialization: first root operation. - Validate the deserialized value against application authorization and domain rules before use. -## Runtime safeguards +## Built-in safeguards Treat native-mode bytes from untrusted sources the same way you would treat untrusted pickle bytes. Native mode can reconstruct Python objects, import modules, invoke reduction hooks, and rebuild @@ -157,7 +157,7 @@ unchanged. Add negative tests for the boundary as well as normal round trips. Verify that the configured reader rejects unexpected application types, excessive nesting, resource-limit violations, and malformed -input. After a failed read, verify that a valid root can still be read with the reusable runtime. +input. After a failed read, verify that a valid root can still be read with the same Fory instance. See [Configuration](configuration.md) for the complete option reference and -[Type Registration](type-registration.md) for the runtime's registration API. +[Type Registration](type-registration.md) for the Fory registration API. diff --git a/docs/object-serialization/rust/basic-serialization.md b/docs/object-serialization/rust/basic-serialization.md index b8fcf9e873..08e189570e 100644 --- a/docs/object-serialization/rust/basic-serialization.md +++ b/docs/object-serialization/rust/basic-serialization.md @@ -211,7 +211,7 @@ all supported carriers, and registration. ## Cross-Language Interoperability -The default xlang format is shared by all Fory runtimes. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. +The default xlang format is shared by all supported Fory implementations. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. Apache Fory™ supports seamless data exchange across Java, Python, C++, Go, Rust, JavaScript/TypeScript, C#, Swift, Dart, Scala, and Kotlin. diff --git a/docs/object-serialization/rust/configuration.md b/docs/object-serialization/rust/configuration.md index f5fb04eefc..1ba92cd25b 100644 --- a/docs/object-serialization/rust/configuration.md +++ b/docs/object-serialization/rust/configuration.md @@ -126,7 +126,7 @@ let fory = Fory::builder() .build(); ``` -Zero is rejected when the runtime is created. +Zero is rejected when the Fory instance is created. ### Unbacked Container Work Budget diff --git a/docs/object-serialization/rust/external-types.md b/docs/object-serialization/rust/external-types.md index 39a51fbf7a..735c33e7e5 100644 --- a/docs/object-serialization/rust/external-types.md +++ b/docs/object-serialization/rust/external-types.md @@ -108,7 +108,7 @@ enum ValueSerializer { } ``` -The target must represent the same runtime unknown carrier for lossless xlang +The target must represent the same in-memory unknown-case carrier for lossless xlang union reads. A third-party crate can remain independent of Fory by declaring a generic enum such as `Value`; the application sets the serializer target to `Value`. A target that cannot carry unknown cases is not eligible diff --git a/docs/object-serialization/rust/index.md b/docs/object-serialization/rust/index.md index 6f1156060e..0db68ae3d0 100644 --- a/docs/object-serialization/rust/index.md +++ b/docs/object-serialization/rust/index.md @@ -35,16 +35,16 @@ The Rust implementation provides versatile and high-performance serialization wi ## Crates -| Crate | Description | Version | -| --------------------------------------------------------------------------- | --------------------------------------------------------- | --------------------------------------------- | -| [`fory`](https://github.com/apache/fory/blob/main/rust/fory) | User-facing API, runtime types, and derive macros | [1.5.0](https://crates.io/crates/fory) | -| [`fory-core`](https://github.com/apache/fory/blob/main/rust/fory-core/) | Lower-level runtime crate for advanced integrations | [1.5.0](https://crates.io/crates/fory-core) | -| [`fory-derive`](https://github.com/apache/fory/blob/main/rust/fory-derive/) | Lower-level procedural macro crate for direct runtime use | [1.5.0](https://crates.io/crates/fory-derive) | +| Crate | Description | Version | +| --------------------------------------------------------------------------- | ----------------------------------------------------- | --------------------------------------------- | +| [`fory`](https://github.com/apache/fory/blob/main/rust/fory) | User-facing API, public Fory types, and derive macros | [1.5.0](https://crates.io/crates/fory) | +| [`fory-core`](https://github.com/apache/fory/blob/main/rust/fory-core/) | Lower-level core crate for advanced integrations | [1.5.0](https://crates.io/crates/fory-core) | +| [`fory-derive`](https://github.com/apache/fory/blob/main/rust/fory-derive/) | Procedural macro crate for direct derive-macro use | [1.5.0](https://crates.io/crates/fory-derive) | Most applications should depend on `fory` only. It re-exports the derive -macros and the public runtime types needed by generated code. Use `fory-core` +macros and the public Fory types needed by generated code. Use `fory-core` or `fory-derive` directly only when intentionally building on the lower-level -runtime crates. +crates. ## Quick Start diff --git a/docs/object-serialization/rust/native.md b/docs/object-serialization/rust/native.md index 084d6ab118..751a71aaba 100644 --- a/docs/object-serialization/rust/native.md +++ b/docs/object-serialization/rust/native.md @@ -108,7 +108,7 @@ Native serialization owns the Rust-specific object surface: - `Box`, `Rc`, `Arc`, `RcWeak`, and `ArcWeak`. - `RefCell` and `Mutex`. - Trait objects such as `Box`, `Rc`, and `Arc`. -- Runtime type dispatch with `Box`, `Rc`, and +- Dynamic type dispatch with `Box`, `Rc`, and `Arc` for registered non-container payloads. Wrap containers in registered structs, enums, or unions, or register an exact-target custom serializer when an opaque EXT/NAMED_EXT representation diff --git a/docs/object-serialization/rust/polymorphism.md b/docs/object-serialization/rust/polymorphism.md index 47ac16ede8..783dee315b 100644 --- a/docs/object-serialization/rust/polymorphism.md +++ b/docs/object-serialization/rust/polymorphism.md @@ -61,7 +61,7 @@ impl Animal for Cat { register_trait_type!(Animal, Dog, Cat); ``` -The concrete list contains runtime value types. Each type must also be +The concrete list contains concrete Rust value types. Each type must also be registered with the `Fory` instance: ```rust diff --git a/docs/object-serialization/rust/security.md b/docs/object-serialization/rust/security.md index 7a17d95fec..abc79510c3 100644 --- a/docs/object-serialization/rust/security.md +++ b/docs/object-serialization/rust/security.md @@ -33,7 +33,7 @@ Before deserialization: first root operation. - Validate the deserialized value against application authorization and domain rules before use. -## Runtime safeguards +## Built-in safeguards Security-related configuration: @@ -52,7 +52,7 @@ Security-related configuration: Add negative tests for the boundary as well as normal round trips. Verify that the configured reader rejects unexpected application types, excessive nesting, resource-limit violations, and malformed -input. After a failed read, verify that a valid root can still be read with the reusable runtime. +input. After a failed read, verify that a valid root can still be read with the same Fory instance. See [Configuration](configuration.md) for the complete option reference and -[Type Registration](type-registration.md) for the runtime's registration API. +[Type Registration](type-registration.md) for the Fory registration API. diff --git a/docs/object-serialization/rust/type-registration.md b/docs/object-serialization/rust/type-registration.md index 162eb4a954..87fe456587 100644 --- a/docs/object-serialization/rust/type-registration.md +++ b/docs/object-serialization/rust/type-registration.md @@ -76,7 +76,7 @@ API: fory.register::(101)?; ``` -The serializer's `Target` is the runtime value type. Registration does not +The serializer's `Target` is the Rust value type. Registration does not require a separate external-type API. At fields, `with` can select an exact carrier serializer such as `VecSerializer`, while recursive `list`, `map`, or `tuple` annotations select serializers at child nodes. At diff --git a/docs/object-serialization/scala/index.md b/docs/object-serialization/scala/index.md index de1d3efec9..7a10630b66 100644 --- a/docs/object-serialization/scala/index.md +++ b/docs/object-serialization/scala/index.md @@ -54,8 +54,10 @@ libraryDependencies += "org.apache.fory" %% "fory-scala" % "1.5.0" ### JDK25+ -Scala uses the Fory Java core when running. On JDK25+, open `java.lang.invoke` to -Fory. Use `ALL-UNNAMED` when Fory is on the classpath: +Scala uses the Fory Java core when running. On JDK25+, opening `java.lang.invoke` to Fory core is +not required, but is recommended. It avoids the current-JDK Unsafe fallback and is required when Unsafe +access is disabled or unavailable, including with `--sun-misc-unsafe-memory-access=deny`. Use +`ALL-UNNAMED` when Fory is on the classpath: ```bash --add-opens=java.base/java.lang.invoke=ALL-UNNAMED diff --git a/docs/object-serialization/scala/native.md b/docs/object-serialization/scala/native.md index 20fd963b97..105ab4ab30 100644 --- a/docs/object-serialization/scala/native.md +++ b/docs/object-serialization/scala/native.md @@ -178,6 +178,6 @@ val employee = Employee( println(fory.deserialize(fory.serialize(employee))) ``` -Use native mode for Scala/JVM-only traffic that needs Scala case classes, -collections, tuples, options, or enums on the JVM runtime path. See +Use native mode for Scala/JVM-only traffic with Scala case classes, collections, +tuples, options, or enums. See [Scala Configuration](configuration.md) for production builder settings. diff --git a/docs/object-serialization/scala/security.md b/docs/object-serialization/scala/security.md index f5f40c61c7..529f5fb9f9 100644 --- a/docs/object-serialization/scala/security.md +++ b/docs/object-serialization/scala/security.md @@ -33,7 +33,7 @@ Before deserialization: first root operation. - Validate the deserialized value against application authorization and domain rules before use. -## Runtime safeguards +## Built-in safeguards Scala uses the Java configuration surface. Keep class registration enabled for production and any untrusted payload source: @@ -68,7 +68,7 @@ Security-related configuration: Add negative tests for the boundary as well as normal round trips. Verify that the configured reader rejects unexpected application types, excessive nesting, resource-limit violations, and malformed -input. After a failed read, verify that a valid root can still be read with the reusable runtime. +input. After a failed read, verify that a valid root can still be read with the same Fory instance. See [Configuration](configuration.md) for the Scala option reference and [Java Type Registration](../java/type-registration.md) for the underlying registration API. diff --git a/docs/object-serialization/swift/basic-serialization.md b/docs/object-serialization/swift/basic-serialization.md index 1f1eaadb3f..4374739db7 100644 --- a/docs/object-serialization/swift/basic-serialization.md +++ b/docs/object-serialization/swift/basic-serialization.md @@ -177,7 +177,7 @@ See [Polymorphism and Dynamic Types](polymorphism.md). ## Cross-Language Interoperability -The default xlang format is shared by all Fory runtimes. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. +The default xlang format is shared by all Fory implementations. The following sections cover its cross-language type mapping, type identity, and interoperability requirements. Fory Swift can exchange payloads with other Fory implementations using the xlang protocol. diff --git a/docs/object-serialization/swift/configuration.md b/docs/object-serialization/swift/configuration.md index 1d3bae58ad..5961790a2a 100644 --- a/docs/object-serialization/swift/configuration.md +++ b/docs/object-serialization/swift/configuration.md @@ -105,7 +105,7 @@ skips leaf values such as strings, binary data, primitive scalars, and dense pri actual process memory can be higher than this value. Leaf values remain protected by byte-availability checks: if the unread input does not contain enough bytes, Fory will not read or create that leaf value. The default limit is a fixed `128 MiB` for all root input forms. A positive -value overrides the default. Explicit non-positive values are rejected when the runtime is created. +value overrides the default. Explicit non-positive values are rejected when the Fory instance is created. `maxUnbackedContainerItems` limits collection elements and map entries whose repeated read bodies do not consume proportional input during one root diff --git a/docs/object-serialization/swift/security.md b/docs/object-serialization/swift/security.md index a03e6c58b5..53dec527d8 100644 --- a/docs/object-serialization/swift/security.md +++ b/docs/object-serialization/swift/security.md @@ -33,7 +33,7 @@ Before deserialization: first root operation. - Validate the deserialized value against application authorization and domain rules before use. -## Runtime safeguards +## Built-in safeguards Security-related configuration: @@ -50,7 +50,7 @@ Security-related configuration: Add negative tests for the boundary as well as normal round trips. Verify that the configured reader rejects unexpected application types, excessive nesting, resource-limit violations, and malformed -input. After a failed read, verify that a valid root can still be read with the reusable runtime. +input. After a failed read, verify that a valid root can still be read with the same Fory instance. See [Configuration](configuration.md) for the complete option reference and -[Type Registration](type-registration.md) for the runtime's registration API. +[Type Registration](type-registration.md) for the Fory registration API. diff --git a/docs/object-serialization/xlang.md b/docs/object-serialization/xlang.md index bfd8ea7b4f..09b7993b7c 100644 --- a/docs/object-serialization/xlang.md +++ b/docs/object-serialization/xlang.md @@ -20,16 +20,16 @@ license: | --- Xlang is Fory's default object serialization mode. It uses one portable binary format across Java, -Python, C++, Go, Rust, JavaScript/TypeScript, C#, Swift, Dart, Scala, and Kotlin. Each runtime's -[Basic Serialization](#runtime-guides) page owns its API and model examples; this page explains the -rules that peers must share. +Python, C++, Go, Rust, JavaScript/TypeScript, C#, Swift, Dart, Scala, and Kotlin. Each +language-specific [Basic Serialization](#language-guides) page documents the relevant API and model +examples; this page explains the rules that peers must share. Read [Core Concepts](core-concepts.md) first for the object graph, schema, reference, and polymorphism concepts shared by xlang and native modes. ## Overview -Use xlang serialization when bytes cross runtime boundaries, including polyglot services, data +Use xlang serialization when bytes cross language boundaries, including polyglot services, data pipelines, and frontend/backend communication. It provides: - Direct serialization of native language models without requiring an IDL. @@ -37,15 +37,15 @@ pipelines, and frontend/backend communication. It provides: - Compatible schema evolution for independently deployed peers. - Optional shared-reference and circular-reference preservation. - Polymorphic values when every concrete type has a portable mapping. -- Out-of-band buffers for large binary and numeric data where the runtime supports them. +- Out-of-band buffers for large binary and numeric data where the Fory implementation supports them. -Use [Native Serialization](native.md) instead when every writer and reader uses the same supported -runtime and the object graph needs language-specific behavior such as Java serialization hooks or -Python pickle-compatible objects. +Use [Native Serialization](native.md) instead when every writer and reader uses one supported Fory +implementation family and the object graph needs language-specific behavior such as Java +serialization hooks or Python pickle-compatible objects. -### Supported Runtimes +### Supported Languages -| Runtime | Package or target | Modes | +| Language | Package or target | Modes | | --------------------- | ------------------------------------------ | ------------ | | Java | `org.apache.fory:fory-core` | xlang/native | | Python | `pyfory` | xlang/native | @@ -124,7 +124,7 @@ message Person { } ``` -Generate the required runtime targets with `foryc`; generated models use consistent field and type +Generate the required language targets with `foryc`; generated models use consistent field and type metadata across those targets. ## Type System and Type Identity @@ -141,9 +141,9 @@ carrier for every xlang type. Important cases include: - Python uses markers such as `pyfory.Int32`, `pyfory.Float16`, and `pyfory.BFloat16` when the native Python type does not express the required width. -- Java, Dart, and other runtimes use annotations or schema metadata where one host type can represent +- Java, Dart, and other languages use annotations or schema metadata where one host type can represent multiple xlang types. -- Reduced-precision `float16` and `bfloat16` values and dense arrays use runtime-specific carriers. +- Reduced-precision `float16` and `bfloat16` values and dense arrays use language-specific carriers. - `list` and dense `array` are distinct schemas. In compatible mode, a direct struct field may adapt between a list and dense bool/numeric array when the element domain is compatible and the actual list contains no unrepresentable null or reference-tracked element. @@ -161,22 +161,22 @@ small contract registry or use generated Fory IDL modules when multiple teams ow ### Static and Dynamic Fields -A statically known field uses its declared serializer without writing a concrete runtime type. A +A statically known field uses its declared serializer without writing a concrete type. A dynamic field carries enough type information to select the concrete registered type. Dynamic metadata is needed for interfaces, abstract types, trait objects, and other polymorphic positions; it is unnecessary for primitives and exact final types. -| Runtime | Dynamic field model | -| ------- | ----------------------------------------------------------------- | -| Java | `@ForyField(dynamic = ...)` controls automatic or forced metadata | -| Python | `pyfory.field(dynamic=...)` controls object-field metadata | -| C++ | `fory::F(...).dynamic(...)` overrides automatic detection | -| Go | Interface fields express dynamic values | -| Rust | Trait-object carriers express dynamic values | +| Language | Dynamic field model | +| -------- | ----------------------------------------------------------------- | +| Java | `@ForyField(dynamic = ...)` controls automatic or forced metadata | +| Python | `pyfory.field(dynamic=...)` controls object-field metadata | +| C++ | `fory::F(...).dynamic(...)` overrides automatic detection | +| Go | Interface fields express dynamic values | +| Rust | Trait-object carriers express dynamic values | Writing dynamic metadata costs space and type-resolution work. Disable it only when the field can never contain another concrete type. Exact annotation and registration examples belong to each -runtime's schema metadata, type registration, and polymorphism pages. +language's schema metadata, type registration, and polymorphism pages. ## Nullability and Reference Tracking @@ -189,7 +189,8 @@ Nullability and reference tracking solve different problems: The wire framing is defined by the [xlang serialization specification](../specification/xlang_serialization_spec.md). Applications -should configure the semantic behavior through runtime APIs rather than depend on flag values. +should configure the semantic behavior through their language-specific Fory APIs rather than depend +on flag values. ### Nullability @@ -227,9 +228,9 @@ Fory fory = Fory.builder() .build(); ``` -Global reference tracking enables the runtime mechanism; field metadata selects which positions +Global reference tracking enables the reference-tracking mechanism; field metadata selects which positions participate. Common field-level controls are Java and Scala `@Ref`, Go `fory:"ref"` tags, Rust -`#[fory(ref = true)]`, and C++ smart-pointer or `fory::F().ref()` metadata. Consult the runtime guide +`#[fory(ref = true)]`, and C++ smart-pointer or `fory::F().ref()` metadata. Consult the language guide because default tracking differs by carrier and language. Reference support also follows the host ownership model. For example, Rust can preserve supported @@ -242,12 +243,12 @@ element, or root type is broader. Every receiving peer must: 1. Register the same concrete type identity. 2. Provide a compatible field schema for that concrete type. -3. Mark or model the position as dynamic when the runtime cannot infer it. +3. Mark or model the position as dynamic when the Fory implementation cannot infer it. 4. Use a concrete type that has a portable xlang mapping. Host-language inheritance alone does not make a type portable. If a shape has no xlang mapping, use -the runtime's native mode for same-language traffic or define a portable model. See the runtime -polymorphism pages for interfaces, trait objects, unions, and generated-code syntax. +native mode for traffic within one Fory implementation family or define a portable model. See the +language polymorphism pages for interfaces, trait objects, unions, and generated-code syntax. ## Schema Evolution @@ -270,7 +271,7 @@ together. Normative compatibility behavior lives in the ## Zero-Copy Serialization -Some runtimes can move large binary or numeric buffers out of the main serialized byte stream. This +Some Fory implementations can move large binary or numeric buffers out of the main serialized byte stream. This avoids copying those buffers into one contiguous payload. The transport flow is: @@ -300,7 +301,7 @@ decoded = fory.deserialize(metadata, buffers=buffers) ``` Go exposes the equivalent callback-buffer flow through its serialization and buffer APIs. Use the -runtime documentation for the current method names and supported buffer carriers. +language guide for the current method names and supported buffer carriers. Out-of-band serialization helps when buffers are large and the transport can send them without an additional copy. For small arrays, callback and multi-buffer transport overhead may cost more than @@ -309,33 +310,33 @@ copying. The application owns buffer ordering, lifetime, and transport framing. ## Troubleshooting -| Symptom | Likely cause | Resolution | -| ---------------------------------------- | --------------------------------------------------- | -------------------------------------------------------------- | -| Type is not registered | Registration missing or performed too late | Register every custom type before the first root operation | -| Type ID or name mismatch | Peers use different identities | Use the same numeric ID or the same namespace and type name | -| Integer overflow or float precision loss | Host carriers use different numeric widths | Follow the type mapping and use explicit width metadata | -| Fields decode incorrectly | Field IDs, names, or types differ | Align field metadata or regenerate all peers from the same IDL | -| Stack overflow on a cyclic graph | Reference tracking is disabled | Enable global and field-level reference tracking | -| Shared objects become duplicates | The value position does not track references | Enable reference tracking for that carrier or field | -| Unsupported host type | The type has no portable xlang representation | Use a portable model or native mode for same-language traffic | -| Schema/hash mismatch | Same-schema peers have different schemas | Align every peer or restore compatible mode | -| Failure after an upgrade | Peers run incompatible protocol versions | Align supported Fory versions and review release notes | -| Payload rejected immediately | One peer wrote native bytes and another reads xlang | Keep all peers on xlang for a cross-language contract | +| Symptom | Likely cause | Resolution | +| ---------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------- | +| Type is not registered | Registration missing or performed too late | Register every custom type before the first root operation | +| Type ID or name mismatch | Peers use different identities | Use the same numeric ID or the same namespace and type name | +| Integer overflow or float precision loss | Host carriers use different numeric widths | Follow the type mapping and use explicit width metadata | +| Fields decode incorrectly | Field IDs, names, or types differ | Align field metadata or regenerate all peers from the same IDL | +| Stack overflow on a cyclic graph | Reference tracking is disabled | Enable global and field-level reference tracking | +| Shared objects become duplicates | The value position does not track references | Enable reference tracking for that carrier or field | +| Unsupported host type | The type has no portable xlang representation | Use a portable model or native mode within one Fory implementation family | +| Schema/hash mismatch | Same-schema peers have different schemas | Align every peer or restore compatible mode | +| Failure after an upgrade | Peers run incompatible protocol versions | Align supported Fory versions and review release notes | +| Payload rejected immediately | One peer wrote native bytes and another reads xlang | Keep all peers on xlang for a cross-language contract | ### Diagnostic Checklist 1. Confirm that every peer uses xlang mode and a mutually supported Fory version. 2. Compare the registered type identity, field IDs or names, numeric widths, nullability, and reference metadata. -3. Reproduce a same-runtime round trip before testing the cross-runtime direction. +3. Reproduce a local round trip in each Fory implementation before testing the cross-language direction. 4. Test both directions for every language pair used in production. 5. Reduce the value to one type and field, then add fields back until the mismatch appears. -6. Inspect the runtime-specific troubleshooting page for generated-code, platform, or API errors. +6. Inspect the language-specific troubleshooting page for generated-code, platform, or API errors. -When diagnosing binary layout, use the specifications and runtime debug facilities. Do not treat a +When diagnosing binary layout, use the specifications and implementation-specific debug facilities. Do not treat a hex dump or internal flag value as a stable application API. -## Runtime Guides +## Language Guides - [Java](java/basic-serialization.md#cross-language-interoperability) - [Python](python/basic-serialization.md#cross-language-interoperability) @@ -352,9 +353,9 @@ hex dump or internal flag value as a stable application API. ## Related Documentation - [Xlang Serialization Format](../specification/xlang_serialization_spec.md) — normative wire format -- [Xlang Type Mapping](../specification/xlang_type_mapping.md) — exact runtime carrier mappings +- [Xlang Type Mapping](../specification/xlang_type_mapping.md) — exact host-language carrier mappings - [Fory IDL and Compiler](../compiler/index.md) — schema-first models and code generation -- [Getting Started](../start/index.md) — installation and first serialization for each runtime +- [Getting Started](../start/index.md) — installation and first serialization for each language - [Row Format](../row-format/index.md) — random-access analytical rows for trusted data ## Operational Best Practices diff --git a/docs/row-format/index.md b/docs/row-format/index.md index 8c901cd074..3375195166 100644 --- a/docs/row-format/index.md +++ b/docs/row-format/index.md @@ -30,7 +30,7 @@ reconstruction as its primary access pattern. ## Choose a Layout -| Layout | Runtime support | Compatibility | +| Layout | Language support | Compatibility | | ------------ | ----------------------- | -------------------------------- | | Standard Row | Java, Python, C++, Rust | Shared Standard Row layout | | Compact Row | Java | Java-only, space-oriented layout | @@ -53,16 +53,16 @@ arrays, and maps use a schema to resolve field positions and element types. The layout, alignment rules, type table, and endianness are defined by the [Row Format specification](../specification/row_format_spec.md). -### Runtime Support +### Language Support -| Runtime | Standard Row compatibility | Runtime guide | Additional integration | -| ------- | -------------------------- | ------------------- | ------------------------------------------------------ | -| Java | Compatible | [Java](java.md) | Arrow conversion; interface and extension-type mapping | -| Python | Compatible | [Python](python.md) | PyArrow schema and table conversion | -| C++ | Compatible | [C++](cpp.md) | Native row readers and writers | -| Rust | Compatible | [Rust](rust.md) | Borrowed struct, array, and map views | +| Language | Standard Row compatibility | Language guide | Additional integration | +| -------- | -------------------------- | ------------------- | ------------------------------------------------------ | +| Java | Compatible | [Java](java.md) | Arrow conversion; interface and extension-type mapping | +| Python | Compatible | [Python](python.md) | PyArrow schema and table conversion | +| C++ | Compatible | [C++](cpp.md) | Native row readers and writers | +| Rust | Compatible | [Rust](rust.md) | Borrowed struct, array, and map views | -Use the runtime guides for installation, schema construction, encoding, random access, partial +Use the language guides for installation, schema construction, encoding, random access, partial reads, and language-specific integrations. ## Compact Row diff --git a/docs/row-format/troubleshooting.md b/docs/row-format/troubleshooting.md index d0ff59e1a0..c5fe6330d3 100644 --- a/docs/row-format/troubleshooting.md +++ b/docs/row-format/troubleshooting.md @@ -31,5 +31,5 @@ handles only for rows that share that schema. ## A nested value appears to require full deserialization -Use the row, array, and map accessors directly. Call the runtime encoder's object reconstruction API -only for the subtree that must become an object. +Use the row, array, and map accessors directly. Call the selected Fory Row encoder's object +reconstruction API only for the subtree that must become an object. diff --git a/docs/security/deserialization.md b/docs/security/deserialization.md index bec502b9f4..6eae0b2f98 100644 --- a/docs/security/deserialization.md +++ b/docs/security/deserialization.md @@ -31,7 +31,7 @@ a `JsonCreator`, but the selected business invariant remains an application policy rather than a Fory protocol security boundary. This model also does not cover trusted in-memory formats. Row format and other -memory-format paths are trusted-data paths unless a runtime explicitly exposes +memory-format paths are trusted-data paths unless a Fory implementation explicitly exposes them as untrusted deserialization APIs. ## Trust Boundaries @@ -119,7 +119,7 @@ accounting boundary. ## Depth And Progress Deserialization paths that recurse through objects, metadata, containers, or -references should enforce the runtime's configured depth limit before crafted +references should enforce the Fory instance's configured depth limit before crafted nesting can exhaust the call stack or bypass cleanup. A malformed input that exceeds the configured depth should fail the root operation instead of continuing unbounded recursion. @@ -283,7 +283,7 @@ The security requirement is to avoid disproportionate preallocation from a declared logical count before enough input bytes justify that capacity. When the repeated element or entry body is proven to consume at least one byte, a reader that allocates or reserves from the declared count should call -`checkReadableBytes(logicalCount)` or the runtime equivalent before that +`checkReadableBytes(logicalCount)` or an equivalent readable-byte check before that allocation. When the body may consume no bytes, the readable-byte requirement may exclude the root operation's remaining unbacked-container allowance. The reader must still account for actual input progress while reading the @@ -298,7 +298,7 @@ segmentation is normal input and is not a security issue by itself. ## Unbacked Container Work Budget -Runtimes enforce a root-scoped limit on count-driven collection elements and +Fory implementations enforce a root-scoped limit on count-driven collection elements and map entries whose repeated read bodies are not backed by input progress. The public option is named `maxUnbackedContainerItems` or the language-equivalent spelling. Its default is `8192`; values must be non-negative, and zero is a @@ -319,15 +319,15 @@ those proven-positive paths. ## Graph Memory Budget -Runtimes should enforce a per-operation approximate gate for estimated memory created by one +Fory implementations should enforce a per-operation approximate gate for estimated memory created by one materialized graph. This is cumulative accounting for graph owners created by one top-level deserialization operation; it is not exact heap measurement and it is not a raw element-slot limit. Actual process memory can be higher than the configured gate. The public configuration is `maxGraphMemoryBytes`. The default is a fixed `128 MiB` for all input forms; positive user configuration overrides the default. Explicit non-positive configuration is -invalid and should be rejected when the runtime is created. The budget is not derived from input -size, and stream budgeting should not depend on dynamic bytes-read accounting. +invalid and should be rejected during configuration or Fory instance creation. The budget is not +derived from input size, and stream budgeting should not depend on dynamic bytes-read accounting. Graph budget accounting should: @@ -352,14 +352,14 @@ Graph budget accounting should: and use primitive/value field widths for inline storage; - preserve existing byte-availability checks before backing allocation or capacity reservation; - skip enum/union as separate owners and skip dedicated string, binary, primitive scalar, primitive - array, and primitive dense-array leaf owners unless a runtime-specific owner section explicitly + array, and primitive dense-array leaf owners unless a language-specific owner section explicitly includes them. Skipped leaf owners must still be gated by remaining input bytes. If the unread input does not contain enough bytes for a string, binary value, primitive scalar, primitive array, or primitive -dense array, the runtime must not read or create that leaf value. +dense array, the reader must not read or create that leaf value. -Each runtime must inspect the concrete owner path before choosing formulas. Reserve self storage +Each Fory implementation must inspect the concrete owner path before choosing formulas. Reserve self storage exactly once at the owner that stores, boxes, or allocates the value. Deserialization facades may reset the budget for each operation, but must not pre-reserve the top-level result type, self bytes, or value storage. @@ -367,7 +367,7 @@ Reference-backed paths reserve parent owner self cost plus reference storage, wh heap owner reserves its own shallow self cost when materialized. Inline/value paths reserve inline element, field, or boxed storage in the holder/allocation owner; top-level value serializers and generated struct/product read paths must not charge their own self storage. -For inline/value collection or map runtimes, the top-level value container itself is not charged by +For inline/value collection or map implementations, the top-level value container itself is not charged by the deserialization facade or by the container serializer only because it is the returned value. Nested value containers are charged as inline slots of the parent holder or as backing storage elements of the outer collection that actually owns those slots. Pointer, box, smart-pointer, or @@ -446,19 +446,19 @@ the complete target and target-ancestor prefix used by an ordinary child. It mus non-public physical field in that prefix; the generator does not scan the referenced assembly for private layout. -Exact external private identities are version-pinned package ABI assertions. Runtime wire access +Exact external private identities are version-pinned package ABI assertions. Generated wire access uses exact accessors and must not fall back to reflection, layout probing, or a different member. -Storage-only private declarations have no runtime accessor, so the application must validate them +Storage-only private declarations have no generated accessor, so the application must validate them against the pinned package version. Dart generators may additionally include public instance fields visible on the target at generation time. Swift macros cannot inspect another type's stored layout and therefore use only -the external declaration. In every runtime, these formulas are resolved during generation and +the external declaration. In every implementation, these formulas are resolved during generation and must not add reflection, layout probing, allocation, or field enumeration to deserialization hot paths. The normal owner rules still apply: a reference target reserves its shallow owner and field storage, while an inline value target is charged by the holder that owns its storage. -### Runtime-Specific Owner Notes +### Language-Specific Owner Notes #### C++ @@ -536,7 +536,7 @@ materialization path, owns that reservation. Boxing, `object`, and dynamic mater reserve a boxed owner when Fory creates the retained box. Owner constants should be real portable lower bounds for the relevant C# object or container shape, not placeholder markers. -Runtimes should not guess object headers, array headers, allocator headers, debug-mode fields, hash +Fory implementations should not guess object headers, array headers, allocator headers, debug-mode fields, hash buckets, tree links, hash-chain links, node headers, map-entry objects, spare blocks, or runtime table layouts unless the owner path has a cheap, stable, explicit lower-bound storage signal and documents the formula. Owner constants should be real lower bounds for the owner shape, not @@ -545,14 +545,14 @@ placeholder markers. ## Skip Semantics Skipping unknown or incompatible data is classified by concrete impact, not by -whether the runtime materializes a temporary value. +whether the Fory implementation materializes a temporary value. Directly consuming encoded contents is useful when it is simple and owned by the -current runtime path. It is not a security requirement for complex fields such -as lists, sets, and maps. A runtime may materialize a value and discard it when +current reader path. It is not a security requirement for complex fields such +as lists, sets, and maps. A Fory implementation may materialize a value and discard it when that preserves the existing serializer ownership model. -For extension, dynamic, or user-owned types, the owning runtime may not always +For extension, dynamic, or user-owned types, the owning Fory implementation may not always have enough information to skip without invoking a registered serializer. In that case, classify the behavior by concrete impact: @@ -643,7 +643,7 @@ one TypeDef. These limits are checked before copying, decompressing, reserving, or allocating from attacker-declared metadata sizes or field counts. The default limits are `maxTypeFields = 512` and `maxTypeMetaBytes = 4096`. -Runtimes should report limit failures as possible malicious data and tell users +Fory implementations should report limit failures as possible malicious data and tell users to increase the exact option only when the data is not malicious. These limits must not introduce validation on metadata cache-hit, generated serializer, or already-resolved type-id hot paths. @@ -673,7 +673,7 @@ The downstream error does not need to be a dedicated reference-protocol error. ## Error Propagation And Cleanup -Fory runtimes may intentionally use lazy error propagation. After a read records +Fory implementations may intentionally use lazy error propagation. After a read records an error, later read steps may continue until the outer operation observes and returns the error. diff --git a/docs/security/index.md b/docs/security/index.md index 66f8cc7e59..b4520729b9 100644 --- a/docs/security/index.md +++ b/docs/security/index.md @@ -9,7 +9,7 @@ samples, issue timelines, or implementation history. Security model documents describe how Fory should classify and prevent security risks while preserving the performance characteristics expected from Fory -serialization runtimes. +serialization implementations. ## Models diff --git a/docs/security/threat-model.md b/docs/security/threat-model.md index 5fea135056..d99e812b69 100644 --- a/docs/security/threat-model.md +++ b/docs/security/threat-model.md @@ -14,7 +14,7 @@ serialize application-owned objects or deserialize encoded Fory data. Fory does not provide a standalone network service, daemon, authentication system, or transport protocol. -Fory can generate service companions for application-provided gRPC runtimes. +Fory can generate service companions for application-provided gRPC implementations. Those companions provide Fory serialization for request and response objects; the application and gRPC stack still own listeners, channels, credentials, authentication, authorization, deadlines, retries, and transport lifecycle. diff --git a/docs/specification/xlang_implementation_guide.md b/docs/specification/xlang_implementation_guide.md index e749d37da4..9d60dc4e3d 100644 --- a/docs/specification/xlang_implementation_guide.md +++ b/docs/specification/xlang_implementation_guide.md @@ -21,12 +21,11 @@ license: | ## Overview -This guide describes the current xlang implementation ownership model used by -the xlang runtimes. +This guide describes the current xlang ownership model used by Fory implementations. The wire format is defined by [Xlang Serialization Spec](xlang_serialization_spec.md). This document is about -service boundaries, operation flow, and internal ownership. New language implementations do not +service boundaries, operation flow, and internal ownership. New Fory implementations do not need the same class names, but they should preserve the same control flow: - root operations stay on the `Fory` facade @@ -202,7 +201,7 @@ The ownership split is: - the serializer provider owns static serialization behavior and, for an external structural serializer, the local schema declaration -- the target owns runtime values, host type identity, storage size, and +- the target owns values of the target type, host type identity, storage size, and dynamic downcasts - the value serializer owns target bodies, complete root values, defaults, value type identity, root/dynamic type information, and value-level @@ -298,8 +297,8 @@ internal static class StatusSerializer ``` External declarations are compile-time generator input only. They are never -instantiated, reflected over by the runtime, registered, reference-published, -or used as wire identities. Runtime type positions, construction, `TypeInfo`, +instantiated, reflected over at runtime, registered, reference-published, +or used as wire identities. All serializer type positions, construction, `TypeInfo`, metadata, reference publication, generated factory keys, roots, fields, dynamic values, and carriers use the target type. @@ -349,7 +348,7 @@ C# carrier composition remains target-based. The resolver recursively binds `Dictionary`, `SortedDictionary`, `SortedList`, `ConcurrentDictionary`, and `NullableKeyDictionary`. Ordinary, external, and custom -serializers use the same carrier bodies. There is no hierarchy runtime lookup, +serializers use the same carrier bodies. There is no hierarchy lookup at runtime, provider object, callback, schema tree, per-element dispatch, or additional value allocation. @@ -373,7 +372,7 @@ Rust represents immutable value-serializer properties with five associated constants on `Serializer`: - `IS_OPTIONAL` means the selected value shape carries Option semantics; -- `IS_POLYMORPHIC` means its concrete target is selected from the runtime +- `IS_POLYMORPHIC` means its concrete target is selected from the application value; - `IS_SHARED_REF` means it uses the existing shared-reference wire behavior; - `IS_WRAPPER` means it is a Fory-owned wrapper serializer without an @@ -401,9 +400,9 @@ or forwards field framing without changing root or value composition. Serializer-provider identity is a host implementation detail and is never encoded. External structural serializers use the same STRUCT, ENUM, or UNION metadata and value format as an equivalent directly supported target. Custom -serializers that are not the runtime's canonical implementation of an existing +serializers that are not the Fory implementation's canonical serializer for an existing built-in use EXT or NAMED_EXT. Serializer-provider separation does not replace -runtime-owned built-in mappings. +implementation-owned built-in mappings. Static generated fields and serializer-selected roots should dispatch directly to the serializer selected by their schema. A Rust field `with = S` selects the @@ -830,9 +829,9 @@ custom serializer targeting one of the same Rust shapes also keeps it false because it owns an independent opaque EXT body. Private built-in registration validates only its expected internal type ID. These semantic checks use the existing serializer contracts and wire categories. Custom EXT registration is -the only runtime consumer of `IS_WRAPPER`. +the only consumer of `IS_WRAPPER`. -Dynamic values should resolve by the concrete target identity. When a runtime +Dynamic values should resolve by the concrete target identity. When a Fory implementation needs both directions, its serializer-provider-to-type-info and target-to-type-info indexes must point to the same immutable registration metadata and serializer harness rather than creating parallel metadata or serialization paths. @@ -1076,7 +1075,7 @@ This policy avoids three inefficient implementation shapes: Scratch buffers remain appropriate when the target representation is not a direct byte target, such as string transcoding, compression, byte-order -conversion that is not performed in place, bit-packed values, or runtimes whose +conversion that is not performed in place, bit-packed values, or implementations whose stream API cannot read into a caller-provided target. For fixed-width primitive arrays, the final result must not become visible to @@ -1104,8 +1103,8 @@ memory budget before allocation or size hinting. The budget state belongs to state. Root facades set or reset the per-operation budget only; they must not pre-reserve root type or root self bytes. `maxGraphMemoryBytes` defaults to a fixed `128 MiB`; positive configuration overrides the default; explicit -non-positive configuration is invalid and must be rejected when the runtime is -created. Do not derive this budget from root input size, and do not add dynamic +non-positive configuration is invalid and must be rejected during configuration or Fory instance +creation. Do not derive this budget from root input size, and do not add dynamic stream bytes-read accounting for this budget. Because the budget is fixed per root, read state should not mirror the configured maximum into a second active-limit field. Use the existing @@ -1136,13 +1135,13 @@ reserve the heap or boxed storage they allocate. Value serializers, including root and generated struct/product read paths, do not reserve their own self storage. Struct/record/POJO/tuple, compatible, generated, and dynamic object owners reserve a nonzero shallow self cost plus shallow field storage only in -reference-object runtimes or dynamic/boxed materialization paths. +reference-object implementations or dynamic/boxed materialization paths. Parents must not recursively include child object, collection, map, string, binary, or primitive dense-array contents. Skip enum/union as separate owners and skip dedicated string, binary, primitive scalar, primitive array, and primitive dense-array leaf owners, but do not skip general inline-value containers such as vectors or lists of value objects. If reference slot size is not cheap or -reliable to query, use a 4-byte reference slot. Native runtimes may use +reliable to query, use a 4-byte reference slot. Native-code implementations may use conservative lower-bound estimates instead of guessing non-portable object, container, allocator, table, node, entry, or debug-layout details. Reject arithmetic overflow before budget comparison or allocation, and keep the @@ -1150,7 +1149,7 @@ existing `checkReadableBytes` proof before backing allocation or capacity reservation. Skipped leaf owners must still be gated by remaining input bytes. If unread bytes are insufficient for a string, binary value, primitive scalar, primitive -array, or primitive dense array, the runtime must not read or create that leaf +array, or primitive dense array, the reader must not read or create that leaf value. For TypeDef or TypeMeta bodies, first prove that the encoded metadata body bytes @@ -1197,7 +1196,7 @@ The exact-local candidate must be derived inside the metadata owner path from the decoded metadata identity: `userTypeId` for id-registered metadata, or `(namespace, typeName)` for name-registered metadata. Do not thread extra expected-type parameters through read callers solely for this check. This rule -applies to every runtime. Java and Python may lazy-build the local encoded +applies to every Fory implementation. Java and Python may lazy-build the local encoded metadata only after this identity lookup selects a local class and the existing class, registration, and deserialization-policy checks for that class have run. @@ -1270,7 +1269,7 @@ When `Config.compatible` is enabled and the struct is marked evolving: classified as compatible when element domains match; the nullable element schema bit alone is not a schema-pair rejection. Actual null element payloads fail in the dense-array reader. Ref-tracked list-element framing is separate - and may remain rejected when the runtime cannot materialize it without + and may remain rejected when the implementation cannot materialize it without generic/reference paths. When `compatible` is disabled and `checkStructVersion` is enabled: @@ -1339,7 +1338,7 @@ In C#, the enum's underlying numeric value is the xlang tag. Java peers for sparse C# enums must declare matching `@ForyEnumId` values instead of relying on declaration ordinals. -Other language implementations should preserve the same wire rule even if the configuration or +Other Fory implementations should preserve the same wire rule even if the configuration or annotation surface differs. A Rust data-carrying enum is an xlang union only when each known variant is unit @@ -1386,7 +1385,7 @@ registration API family. Ordinary Dart `ForyStruct` inheritance is a code-generation-time field discovery, normalization, access, construction, and flattening change. It does -not redesign the runtime reference protocol. +not redesign the reference protocol. For a concrete annotated child, the generator walks the instantiated superclass and applied-mixin storage chain rather than only the child's direct @@ -1518,7 +1517,7 @@ proof. The concrete child owns one `GeneratedStructSchema`, one canonical field sort, one serializer and descriptor cache, one reconstruction, one reference publication path, and one graph-memory owner. Parent serializers are neither -nested nor invoked, and parent runtime registration is not required. A +nested nor invoked, and parent type registration is not required. A separately annotated concrete parent has its own independently flattened schema only for values of that exact type. @@ -1591,7 +1590,7 @@ registration identity. The generator must analyze ordinary and external structs through one struct model and one emitter. Private generated symbol names come from the declaration -name. Every runtime type position uses the target type: `Serializer`, +name. Every generated serializer type position uses the target type: `Serializer`, `GeneratedStructSchema`, read and write signatures, constructor calls, schema `type`, and generated-module dispatch. @@ -1626,7 +1625,7 @@ paths remain the only runtime paths. Registration is keyed by `Target` through the generated module and the existing generated registration API. Direct roots, generated fields, dynamic values, and recursive collection/map children resolve the same target registration. -Dart root collections retain their existing untyped outer runtime shapes. +Dart root collections retain their existing untyped outer shapes. ## Directory Layout diff --git a/docs/specification/xlang_serialization_spec.md b/docs/specification/xlang_serialization_spec.md index 6ce845417c..9af0f9d2c2 100644 --- a/docs/specification/xlang_serialization_spec.md +++ b/docs/specification/xlang_serialization_spec.md @@ -145,9 +145,9 @@ wire identity. without adding a wire identity or repeated registration lookup; any containing schema metadata owns the prior identity validation. The carrier serializer itself remains unregistered in every case. -- A custom serializer that is not the runtime's +- A custom serializer that is not the Fory implementation's canonical implementation of an existing built-in MUST use the existing EXT - or NAMED_EXT form. This serializer-provider separation does not replace runtime-owned + or NAMED_EXT form. This serializer-provider separation does not replace implementation-owned built-in mappings. - Serializer-provider, external structural serializer, or generated-code type names MUST NOT change the encoded type ID, registered user ID or name, TypeDef, field order, schema hash, @@ -261,7 +261,7 @@ metadata. The reader must decide from the collection payload: if the payload actually carries a null element, the local `array` field must raise a compatible-read error. Null list elements must not be coerced to dense-array default values. Reference-tracked list-element framing is separate from -nullable element schema. A runtime that cannot materialize ref-tracked list +nullable element schema. A Fory implementation that cannot materialize ref-tracked list elements into a dense array without generic/reference paths may reject that field during compatible classification; if it accepts the field, reference payloads that cannot be represented as dense array element values must fail @@ -1597,7 +1597,7 @@ Date represents a date without timezone. It is encoded as: - `days` (varint64): signed count of days since the Unix epoch (`1970-01-01`) The value is reconstructed as `LocalDate.ofEpochDay(days)` or the equivalent calendar-date constructor in -the target language implementation. +the target Fory implementation. This `varint64` encoding applies to xlang serialization only. Native, language-specific local-date encodings are unchanged. @@ -1850,7 +1850,7 @@ A union payload is: ``` `case_id` is the union alternative tag number. -Runtime APIs MAY expose zero-based ordinal indexes for generic union carriers; +Fory APIs MAY expose zero-based ordinal indexes for generic union carriers; those ordinals are valid wire `case_id` values when they are the schema's alternative IDs. @@ -1875,7 +1875,7 @@ numeric type IDs, the type ID byte is the complete value type metadata and the payload writer MAY use the stored wire type ID to preserve fixed, variable, or tagged integer encodings when the decoded value has the expected concrete value type. These scalar numeric payloads are not reference-tracked, so their ref metadata -is `NotNullValue`. Otherwise it MUST fall back to the language implementation's +is `NotNullValue`. Otherwise it MUST fall back to the Fory implementation's ordinary polymorphic Any-value writer. Unknown carriers are implementation-provided forward-compatibility containers, not entries in the local schema case table; schema-defined union cases MAY use `0..N`. When an unknown carrier is written diff --git a/docs/specification/xlang_type_mapping.md b/docs/specification/xlang_type_mapping.md index 800360f215..aa89ae8a85 100644 --- a/docs/specification/xlang_type_mapping.md +++ b/docs/specification/xlang_type_mapping.md @@ -115,7 +115,7 @@ Notes: - C# external-type serialization maps a third-party class/struct or enum through a local `ForyStruct(Target = typeof(...))` or - `ForyEnum(Target = typeof(...))` serializer declaration. The runtime target + `ForyEnum(Target = typeof(...))` serializer declaration. The target type still uses the C# mapping shown above; declaration ownership is not a wire distinction. - Python `pyfory.Float16` and `pyfory.BFloat16` are reserved annotation markers; scalar values deserialize as native Python `float`. @@ -155,7 +155,7 @@ Notes: payload contains a null element, the dense-array reader raises a compatible-read error instead of coercing the value. Reference-tracked list-element framing is separate from nullable element schema and may be rejected during compatible field classification when the local matched field is - `array` and the runtime cannot materialize it without generic/reference paths. + `array` and the Fory implementation cannot materialize it without generic/reference paths. - `binary` and `array` remain distinct schema kinds. In schema-compatible struct/class field matching only, a direct top-level `binary` field may be read as a direct top-level `array` field and the reverse may be read as the same byte sequence. This rule does not apply inside diff --git a/docs/start/cpp.md b/docs/start/cpp.md index bc8384134b..ac0da1011a 100644 --- a/docs/start/cpp.md +++ b/docs/start/cpp.md @@ -33,7 +33,7 @@ cmake --version ## Object Serialization -Use xlang mode for data shared with other Fory runtimes or native mode for +Use xlang mode for data shared with Fory implementations in other languages or native mode for C++-only data. Fetch a released source tree and link the serialization target: ```cmake title="CMakeLists.txt" diff --git a/docs/start/csharp.md b/docs/start/csharp.md index 0167f6b0ad..8ab6e85791 100644 --- a/docs/start/csharp.md +++ b/docs/start/csharp.md @@ -21,7 +21,7 @@ license: | Fory C# provides xlang Object Serialization, generated models, and Fory gRPC. The `Apache.Fory` NuGet package requires .NET 8 or later and includes both the -runtime and source generator. +serialization library and source generator. ## Verify the Toolchain diff --git a/docs/start/index.md b/docs/start/index.md index ea48248b39..cfc88ef686 100644 --- a/docs/start/index.md +++ b/docs/start/index.md @@ -19,8 +19,8 @@ license: | limitations under the License. --- -Start with a runtime page below. Each page includes a release-pinned installation, -a runnable object-serialization round trip, the modes supported by that runtime, +Start with a language page below. Each page includes a release-pinned installation, +a runnable object-serialization round trip, the modes available for that language, and a short path into every additional Fory capability available there. Apache Fory™ releases are available as source artifacts and language-specific @@ -29,19 +29,19 @@ packages. For source downloads, see the Apache Fory™ ## First Five Minutes -1. Choose the runtime used by your application. -2. Install the package shown on that runtime page. +1. Choose the language used by your application. +2. Install the package shown on that language page. 3. Run its minimal serialize/deserialize example. -4. Select xlang mode for cross-language data or native mode for same-runtime data - when both are available. +4. Select xlang mode for cross-language data or native mode for data handled by one Fory + implementation family when both are available. 5. Continue to the capability guide for production configuration and advanced APIs. -## Choose a Runtime +## Choose a Language -Each runtime page provides a release-pinned installation snippet, a minimal +Each language page provides a release-pinned installation snippet, a minimal round trip for an application project, and the next capability-specific steps: -| Runtime | Setup | +| Language | Setup | | --------------------- | -------------------------------------- | | Java | [Java](java.md) | | Python | [Python](python.md) | @@ -57,15 +57,15 @@ round trip for an application project, and the next capability-specific steps: ## What You Can Build -| Capability | Use it for | Available runtimes | Detailed guide | +| Capability | Use it for | Available languages | Detailed guide | | -------------------- | ------------------------------------------------------------------------------ | ---------------------------------------------------------------- | -------------------------------------------------------- | -| Object Serialization | Reconstruct object graphs, including shared references and schema changes | All runtimes | [Object Serialization](../object-serialization/index.md) | +| Object Serialization | Reconstruct object graphs, including shared references and schema changes | All languages | [Object Serialization](../object-serialization/index.md) | | Row Format | Trusted analytical data with zero-copy, random, or partial field access | Java, Python, C++, Rust | [Row Format](../row-format/index.md) | | Fory JSON | High-performance standard JSON mapping | Java | [Fory JSON](../json/index.md) | -| Fory IDL | Generate native models and serializers from Fory, protobuf, or FlatBuffers IDL | All runtimes | [Fory IDL and Compiler](../compiler/index.md) | +| Fory IDL | Generate native models and serializers from Fory, protobuf, or FlatBuffers IDL | All languages | [Fory IDL and Compiler](../compiler/index.md) | | Fory gRPC | Use generated models over normal gRPC transports with Fory-encoded messages | Java, Python, C++, Go, Rust, JavaScript, C#, Dart, Scala, Kotlin | [Fory gRPC](../grpc/index.md) | Object Serialization uses xlang mode for portable cross-language data. Java, -Python, C++, Go, Rust, Scala, and Kotlin also offer native mode for -same-runtime data. Use [Choose a Format](../introduction/choose-a-format.md) +Python, C++, Go, Rust, Scala, and Kotlin also offer native mode for data handled by one Fory +implementation family. Use [Choose a Format](../introduction/choose-a-format.md) when you have not yet chosen a format. diff --git a/docs/start/java.md b/docs/start/java.md index bc38eedafd..fbd52f4440 100644 --- a/docs/start/java.md +++ b/docs/start/java.md @@ -36,7 +36,7 @@ mvn -version ## Object Serialization Use Object Serialization for object graphs. Xlang mode produces data that other -Fory runtimes can read; native mode supports a broader JVM object surface. +Fory implementations in other languages can read; native mode supports a broader JVM object surface. Maven: @@ -124,7 +124,7 @@ object mapping, annotations, Android, GraalVM, and security. - **Fory IDL and Compiler** generates Java models and registration helpers from Fory IDL, protobuf IDL, or FlatBuffers IDL. See [Compiler Getting Started](../compiler/getting-started.md) and the [Java generated-code guide](../compiler/generated-code/java.md). - **Fory gRPC** uses normal grpc-java transports with Fory-encoded request and response objects. See [Java gRPC](../grpc/java.md). -## Runtime Notes +## Platform Notes - On JDK 25 and later, follow the setup in [Java Object Serialization](../object-serialization/java/index.md). diff --git a/docs/start/kotlin.md b/docs/start/kotlin.md index e2fe8f74ab..96ceb7a4f9 100644 --- a/docs/start/kotlin.md +++ b/docs/start/kotlin.md @@ -32,7 +32,7 @@ java -version ## Object Serialization -Add the runtime to the application module: +Add the Fory Kotlin library to the application module: ```kotlin title="build.gradle.kts" dependencies { @@ -67,8 +67,8 @@ If the project applies Gradle's `application` plugin, run its application task: ./gradlew run ``` -Use xlang mode for data shared with other Fory runtimes or native mode for -Kotlin/JVM-only data. Continue with +Use xlang mode when a peer uses a different Fory implementation family; use native mode for data +within the JVM Fory implementation family. Continue with [Kotlin Object Serialization](../object-serialization/kotlin/index.md), [xlang](../object-serialization/kotlin/basic-serialization.md#cross-language-interoperability), or [native mode](../object-serialization/kotlin/native.md). @@ -77,4 +77,4 @@ Kotlin/JVM-only data. Continue with - **Fory IDL and Compiler** generates Kotlin models and registration helpers through KSP. See [Compiler Getting Started](../compiler/getting-started.md) and the [Kotlin generated-code guide](../compiler/generated-code/kotlin.md). - **Fory gRPC** uses grpc-kotlin and grpc-java transports with Fory-encoded messages. See [Kotlin gRPC](../grpc/kotlin.md). -- **Android** uses generated serializers with the same Fory Kotlin runtime. See [Android Object Serialization](../object-serialization/java/android.md). +- **Android** uses generated serializers with the same Fory Kotlin library. See [Android Object Serialization](../object-serialization/java/android.md). diff --git a/docs/start/scala.md b/docs/start/scala.md index 5e8a83c51b..060b4df090 100644 --- a/docs/start/scala.md +++ b/docs/start/scala.md @@ -20,7 +20,7 @@ license: | --- Fory Scala provides binary Object Serialization, generated models, and Fory -gRPC. The runtime artifact supports Scala 2.13 and Scala 3; generated Scala +gRPC. The Fory Scala artifact supports Scala 2.13 and Scala 3; generated Scala models require Scala 3. ## Verify the Toolchain @@ -33,7 +33,7 @@ sbt --version ## Object Serialization -Add the runtime to `build.sbt`: +Add the Fory Scala library to `build.sbt`: ```sbt ThisBuild / scalaVersion := "3.3.1" @@ -66,8 +66,8 @@ object ScalaExample { sbt run ``` -Use xlang mode for data shared with other Fory runtimes or native mode for -Scala/JVM-only data. Continue with +Use xlang mode when a peer uses a different Fory implementation family; use native mode for data +within the JVM Fory implementation family. Continue with [Scala Object Serialization](../object-serialization/scala/index.md), [xlang](../object-serialization/scala/basic-serialization.md#cross-language-interoperability), or [native mode](../object-serialization/scala/native.md). diff --git a/java/README.md b/java/README.md index d35d9a7a61..e9a3e9a2b8 100644 --- a/java/README.md +++ b/java/README.md @@ -137,8 +137,9 @@ dependencies { ### JDK25+ -On JDK25+, open `java.lang.invoke` to Fory. Use `ALL-UNNAMED` when Fory is on -the classpath: +On JDK25+, opening `java.lang.invoke` to Fory core is not required, but is recommended. It avoids the +current-JDK Unsafe fallback and is required when Unsafe access is disabled or unavailable, including +with `--sun-misc-unsafe-memory-access=deny`. Use `ALL-UNNAMED` when Fory is on the classpath: ```bash --add-opens=java.base/java.lang.invoke=ALL-UNNAMED diff --git a/java/fory-core/src/main/java/org/apache/fory/platform/internal/_JDKAccess.java b/java/fory-core/src/main/java/org/apache/fory/platform/internal/_JDKAccess.java index d88bba3cf2..5a105a6156 100644 --- a/java/fory-core/src/main/java/org/apache/fory/platform/internal/_JDKAccess.java +++ b/java/fory-core/src/main/java/org/apache/fory/platform/internal/_JDKAccess.java @@ -70,8 +70,8 @@ public class _JDKAccess { JDK_CONCURRENT_FIELD_ACCESS = false; JDK_PROXY_FIELD_ACCESS = false; } else if (JdkVersion.MAJOR_VERSION >= 25) { - // JDK25+ zero-Unsafe mode requires java.base/java.lang.invoke to be opened to fory-core. - // Missing that open is an invalid runtime configuration, not a fallback signal. + // JDK25+ prefers the java.lang.invoke open and falls back to current-JDK Unsafe when absent. + // Keep the access capabilities enabled so the selected _Lookup path owns that decision. JDK_INTERNAL_FIELD_ACCESS = true; JDK_LANG_FIELD_ACCESS = true; JDK_COLLECTION_FIELD_ACCESS = true; @@ -101,8 +101,10 @@ public static Lookup _trustedLookup(Class objectClass) { } public static String jdk25AccessMessage() { - return "JDK25 zero-Unsafe mode requires java.base/java.lang.invoke to be open to Fory. " - + "Use --add-opens=java.base/java.lang.invoke=ALL-UNNAMED when Fory is on the " + return "On JDK25+, opening java.base/java.lang.invoke to Fory core is not required, but " + + "is recommended. It is required when the current-JDK Unsafe fallback is disabled or " + + "unavailable. Use " + + "--add-opens=java.base/java.lang.invoke=ALL-UNNAMED when Fory is on the " + "classpath, or --add-opens=java.base/java.lang.invoke=org.apache.fory.core when " + "Fory is on the module path."; } diff --git a/java/fory-json/README.md b/java/fory-json/README.md index ad6f1ab8fd..0e46a6d4f6 100644 --- a/java/fory-json/README.md +++ b/java/fory-json/README.md @@ -52,8 +52,9 @@ Gradle: implementation("org.apache.fory:fory-json:1.5.0") ``` -On JDK 25 and later, open `java.lang.invoke` to Fory core. Use -`ALL-UNNAMED` on the classpath: +On JDK 25 and later, opening `java.lang.invoke` to Fory core is not required, but is recommended. It avoids +the current-JDK Unsafe fallback and is required when Unsafe access is disabled or unavailable, +including with `--sun-misc-unsafe-memory-access=deny`. Use `ALL-UNNAMED` on the classpath: ```bash --add-opens=java.base/java.lang.invoke=ALL-UNNAMED