This is an automated email from the ASF dual-hosted git repository.
chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory-site.git
The following commit(s) were added to refs/heads/main by this push:
new f38ea9a551 π synced local 'docs/guide/' with remote 'docs/guide/'
f38ea9a551 is described below
commit f38ea9a551c79008fd805886c45c82472197888e
Author: chaokunyang <[email protected]>
AuthorDate: Mon Jul 13 05:03:20 2026 +0000
π synced local 'docs/guide/' with remote 'docs/guide/'
---
docs/guide/java/index.md | 4 +
docs/guide/java/json-support.md | 603 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 607 insertions(+)
diff --git a/docs/guide/java/index.md b/docs/guide/java/index.md
index bf09b4e861..e276e6d52f 100644
--- a/docs/guide/java/index.md
+++ b/docs/guide/java/index.md
@@ -21,6 +21,9 @@ license: |
Apache Foryβ’ provides blazingly fast Java object serialization with JIT
compilation and zero-copy techniques. Java supports both xlang mode and native
mode. Xlang mode is the default cross-language wire format and uses compatible
schema evolution. Native mode is the Java-only wire format for same-language
object serialization, JDK serialization replacement behavior, framework
replacement, and Java-native object graph features.
+Fory also provides a separate [JSON codec](json-support.md) for interoperable
text payloads. JSON is
+not the native or xlang binary protocol and has its own object-mapping
annotations and limits.
+
## Features
### High Performance
@@ -249,5 +252,6 @@ ThreadSafeFory threadLocalFory = Fory.builder()
- [Custom Serializers](custom-serializers.md) - Implement custom serializers
- [Xlang Serialization](xlang-serialization.md) - Serialize data for other
languages
- [Native Serialization](native-serialization.md) - Java-only serialization
features
+- [JSON Support](json-support.md) - Complete Fory JSON user guide
- [Static Generated Serializers](static-generated-serializers.md) -
Annotation-processor static generated serializers for `@ForyStruct`
- [GraalVM Support](graalvm-support.md) - Build-time serializer compilation
for native images
diff --git a/docs/guide/java/json-support.md b/docs/guide/java/json-support.md
new file mode 100644
index 0000000000..fe1da7a904
--- /dev/null
+++ b/docs/guide/java/json-support.md
@@ -0,0 +1,603 @@
+---
+title: JSON Support
+sidebar_position: 19
+id: json_support
+license: |
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+Fory JSON is Apache Fory's thread-safe Java JSON codec. It supports Java
objects, records,
+immutable creator-based classes, common JDK types, generic containers, exact
custom codecs, and
+finite annotation-declared polymorphism through interpreted and
runtime-generated codecs.
+
+Fory JSON is separate from Fory's binary native and xlang protocols. Use JSON
for interoperable
+text payloads such as HTTP APIs, browser traffic, logs, and configuration. Use
the binary protocol
+when you need reference identity, circular graphs, cross-language schema
metadata, or Fory's
+binary-only features.
+
+## Requirements and installation
+
+The module targets Java 8 bytecode. Record mapping requires Java 17 or later.
+
+Fory JSON is currently available from the source tree as `1.4.0-SNAPSHOT`.
Until a published Fory
+release contains the module, install it locally from the repository root:
+
+```bash
+cd java
+mvn -pl fory-json -am -DskipTests install
+```
+
+Maven:
+
+```xml
+<dependency>
+ <groupId>org.apache.fory</groupId>
+ <artifactId>fory-json</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+</dependency>
+```
+
+Gradle, using `mavenLocal()` for the snapshot:
+
+```kotlin
+implementation("org.apache.fory:fory-json:1.4.0-SNAPSHOT")
+```
+
+Keep all Fory modules on the same version. Replace the snapshot with the
released version that
+contains `fory-json` after publication.
+
+### JDK 25 and later
+
+Open `java.lang.invoke` to Fory core. On the classpath:
+
+```bash
+--add-opens=java.base/java.lang.invoke=ALL-UNNAMED
+```
+
+On the module path:
+
+```bash
+--add-opens=java.base/java.lang.invoke=org.apache.fory.core
+```
+
+Fory JSON's JPMS module name is `org.apache.fory.json`.
+
+## Quick start
+
+Create one `ForyJson` instance and reuse it. It is thread-safe and has no
close lifecycle.
+
+```java
+import java.nio.charset.StandardCharsets;
+import org.apache.fory.json.ForyJson;
+
+public final class JsonExample {
+ private static final ForyJson JSON = ForyJson.builder().build();
+
+ public static final class User {
+ public long id;
+ public String name;
+
+ public User() {}
+
+ User(long id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+ }
+
+ public static void main(String[] args) {
+ User input = new User(7, "Alice");
+ String text = JSON.toJson(input);
+ byte[] utf8 = JSON.toJsonBytes(input);
+
+ User fromText = JSON.fromJson(text, User.class);
+ User fromUtf8 = JSON.fromJson(utf8, User.class);
+
+ System.out.println(text);
+ System.out.println(new String(utf8, StandardCharsets.UTF_8));
+ System.out.println(fromText.name + " / " + fromUtf8.name);
+ }
+}
+```
+
+Unknown input properties are skipped. Null object properties are omitted by
default. JSON member
+order is not a compatibility contract.
+
+## Reading and writing
+
+Fory JSON supports String and UTF-8 byte input/output. There is no
`InputStream` parsing API.
+
+| Operation | Runtime type | Declared `Class`
| Declared `TypeRef` |
+| -------------------- | ------------------------- |
------------------------------- | ---------------------------------- |
+| String output | `toJson(value)` | `toJson(value, type)`
| `toJson(value, typeRef)` |
+| UTF-8 bytes | `toJsonBytes(value)` | `toJsonBytes(value,
type)` | `toJsonBytes(value, typeRef)` |
+| UTF-8 `OutputStream` | `writeJsonTo(value, out)` | `writeJsonTo(value, type,
out)` | `writeJsonTo(value, typeRef, out)` |
+| String input | - | `fromJson(text, type)`
| `fromJson(text, typeRef)` |
+| UTF-8 input | - | `fromJson(bytes, type)`
| `fromJson(bytes, typeRef)` |
+
+Parsing consumes exactly one value and rejects trailing non-whitespace. String
and byte-array
+outputs are detached from internal buffers.
+
+`writeJsonTo` buffers the complete document, performs one
`OutputStream.write`, and neither flushes
+nor closes the stream. It is not incremental streaming. I/O failures are
wrapped in
+`ForyJsonException`.
+
+### Generic and declared types
+
+Use `TypeRef` for generic roots:
+
+```java
+import java.util.List;
+import org.apache.fory.reflect.TypeRef;
+
+TypeRef<List<User>> usersType = new TypeRef<List<User>>() {};
+List<User> users = json.fromJson("[{\"id\":7,\"name\":\"Alice\"}]", usersType);
+String encoded = json.toJson(users, usersType);
+```
+
+Typed writes require fully bound types and reject wildcards and type
variables. Values must be
+assignable to the declared raw type. The declared schema controls
serialization, including nested
+generic element types and closed subtype metadata.
+
+Use a declared base type when it owns `JsonSubTypes`:
+
+```java
+Shape shape = new Circle(2);
+
+json.toJson(shape); // Concrete runtime representation
+json.toJson(shape, Shape.class); // Configured Shape subtype representation
+```
+
+For `List<Shape>`, use `new TypeRef<List<Shape>>() {}` so each element retains
the declared subtype
+schema.
+
+## Thread safety and code generation
+
+`ForyJson` is immutable and thread-safe after `build()`. Registered codecs and
type checkers are
+shared and must also be thread-safe.
+
+Code generation and asynchronous compilation are enabled by default. Disable
them for diagnostics
+or environments that prohibit runtime compilation:
+
+```java
+ForyJson json =
+ ForyJson.builder()
+ .withCodegen(false)
+ .withAsyncCompilation(false)
+ .build();
+```
+
+`withConcurrencyLevel` controls reusable operation states, not a caller limit.
Extra concurrent
+operations use temporary state rather than one global lock.
+
+## Object mapping
+
+Default discovery merges members with the same Java logical property name:
+
+- eligible instance fields across the hierarchy, regardless of Java visibility;
+- public non-static `getX()` and boolean `isX()` getters;
+- public non-static void `setX(value)` setters.
+
+Static, transient, synthetic, and `Class<?>` fields are excluded. Class-valued
accessors and
+`getClass()` are excluded. An annotation on an ineligible member fails rather
than becoming a
+silent no-op.
+
+An ordinary final field is a write source but not a mutable read sink. Use a
record, `JsonCreator`,
+or custom codec for immutable construction. Records use their canonical
constructor.
+
+Enable field-only discovery with:
+
+```java
+ForyJson json = ForyJson.builder().withFieldMode(true).build();
+```
+
+In field mode, getter/setter annotations are invalid. For ordinary properties,
unknown members are
+skipped and duplicate members use the last value. Polymorphic discriminator
members are stricter
+and must occur exactly once. JSON null is rejected for primitive targets. Most
reference targets
+return null, but a selected built-in or custom codec may define another
result; declared Optional
+targets return the corresponding empty Optional.
+
+An ordinary class with a no-argument constructor runs it before readable
properties are assigned,
+so missing properties retain values established by field initializers or the
constructor. On an
+ordinary JVM, a class without such a constructor is allocated without running
its constructors or
+field initializers, and missing properties retain JVM zero or null values.
Android cannot construct
+an ordinary class without a usable no-argument constructor. GraalVM native
image on JDK 25 and
+later also requires one for most ordinary classes; the supported exception is
a `Serializable`
+class whose first non-serializable superclass is `Object`.
+
+For portable construction, use a record, `JsonCreator`, or a no-argument
constructor. Do not use an
+ordinary constructor as a deserialization completion hook: property assignment
follows a
+no-argument constructor, while constructor-bypassing paths do not run it.
+
+## Supported Java types
+
+| Group | Types and behavior
|
+| ------------------ |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
+| Scalars | Primitive and boxed booleans/numbers/chars, strings and
string builders, `BigInteger`, `BigDecimal`, Fory half-precision numbers, enums
|
+| Containers | Primitive/boxed/object arrays; collection, list, set,
queue, deque, blocking, sorted, and navigable interfaces; map, sorted-map,
navigable-map, and concurrent-map interfaces; supported concrete
implementations; `EnumSet`; `EnumMap`; `Optional` variants; atomic values and
arrays |
+| Time | `Date`, `Calendar`, `TimeZone`, Java time types,
supported chronology dates, optional `java.sql.Date`, `Time`, and `Timestamp`
|
+| Other JDK | `UUID`, `URI`, `File`, `Path`, `Locale`, `Charset`,
`Currency`, `Pattern`, `BitSet`, `ByteBuffer`
|
+| Optional libraries | Guava `ImmutableList`, `ImmutableSet`,
`ImmutableSortedSet`, `ImmutableMap`, `ImmutableBiMap`, `ImmutableSortedMap`,
and `ImmutableIntArray` when Guava is present
|
+| Objects | Mutable concrete classes, records, creator classes,
`JsonObject`, `JsonArray`
|
+
+Interfaces are reconstructed with appropriate standard mutable
implementations. `ArrayBlockingQueue`,
+`Arrays.asList` results, JDK immutable collections,
empty/singleton/unmodifiable wrappers,
+constructor-constrained implementations, and unlisted Guava immutable
implementations cannot be
+reconstructed. Guava remains optional.
+
+Non-finite float/double values use quoted `"NaN"`, `"Infinity"`, and
`"-Infinity"` tokens.
+
+### Built-in representations
+
+| Java type |
JSON representation
|
+| ------------------------------------------------------------------------- |
-------------------------------------------------------------------------------------------------------------------
|
+| Enum |
Constant name string
|
+| `Date`, `Calendar`, `java.sql.Date`, `Time`, `Timestamp` |
Epoch-millisecond number
|
+| `TimeZone` |
Time-zone ID string
|
+| Java time and supported chronology date types |
Standard textual string
|
+| `UUID`, `URI`, `File`, `Path`, `Locale`, `Charset`, `Currency`, `Pattern` |
Type-specific text string; `File` and `Path` use path text, `Locale` uses a
language tag, and `Pattern` loses flags |
+| `BitSet` |
Array of signed `long` words
|
+| `ByteBuffer` |
Array of signed byte values from position to limit
|
+| Optional and atomic wrappers |
Contained scalar, array, or value directly
|
+
+`Calendar` is reconstructed as a new `GregorianCalendar`, so its original
subtype, time zone, and
+other configuration are not retained. A null Optional reference and an empty
Optional both write
+JSON null; reading JSON null as a declared Optional type returns the
corresponding empty Optional.
+
+### Dynamic JSON trees
+
+Reading `Object.class` produces natural JSON values:
+
+| JSON | Java |
+| ------------------- | ------------------------------------------ |
+| Object | `JsonObject` |
+| Array | `JsonArray` |
+| String/boolean/null | `String`, `Boolean`, null |
+| Integer | `Long`, or `BigInteger` outside long range |
+| Fraction/exponent | `Double` |
+
+`JsonObject` preserves insertion order and `JsonArray` is mutable.
+
+### Map keys
+
+Declared keys support String, byte, short, int, long, their boxed types, and
enums. `Object` keys
+can write String, number, boolean, character, and enum values, but read back
as strings. Null keys
+are rejected.
+
+## Builder configuration
+
+| Method | Default
| Effect |
+| ---------------------------- | --------------------------------------------
| ------------------------------------------------------ |
+| `writeNullFields` | `false`
| Default null-property inclusion |
+| `withCodegen` | `true`
| Generated object codecs |
+| `withAsyncCompilation` | `true`
| Asynchronous generated-code compilation |
+| `withFieldMode` | `false`
| Field-only discovery when true |
+| `withPropertyNamingStrategy` | `LOWER_CAMEL_CASE`
| Naming of properties without explicit names |
+| `withClassLoader` | Snapshotted context loader, then Fory loader
| Resolve annotation subtype class names |
+| `maxDepth` | `20`
| Maximum nested object/array depth |
+| `withConcurrencyLevel` | `max(1, 2 * processors)`
| Reusable operation-state count |
+| `withBufferSizeLimitBytes` | 2 MiB
| Reusable capacity retained by each pooled writer |
+| `registerCodec` | None
| Exact-class complete-value codec |
+| `withTypeChecker` | None
| Application policy in addition to Fory's disallow list |
+
+Depth, concurrency, and retained buffer limits must be positive. The buffer
setting does not limit
+output size. Builder changes after `build()` do not mutate an existing runtime.
+
+## Annotations
+
+Fory JSON provides only `JsonProperty`, `JsonIgnore`, `JsonCreator`, and
`JsonSubTypes` under
+`org.apache.fory.json.annotation`. They are not Jackson, Gson, or Fory
binary-protocol annotations.
+
+```java
+import org.apache.fory.json.PropertyNamingStrategy;
+import org.apache.fory.json.annotation.JsonCreator;
+import org.apache.fory.json.annotation.JsonIgnore;
+import org.apache.fory.json.annotation.JsonProperty;
+import org.apache.fory.json.annotation.JsonSubTypes;
+```
+
+### `JsonProperty`
+
+An annotation on a field, getter, or setter configures the complete merged
logical property:
+
+```java
+@JsonProperty("user_id")
+private long id;
+
+@JsonProperty(include = JsonProperty.Include.ALWAYS)
+private String displayName;
+```
+
+Supported inclusion values are:
+
+- `DEFAULT`: inherit `writeNullFields`;
+- `ALWAYS`: include null;
+- `NON_NULL`: omit null.
+
+Inclusion affects writing only. Identical repeated declarations are allowed;
conflicting explicit
+names or non-default policies fail. Two properties cannot normalize to the
same JSON name.
+`NON_EMPTY`, aliases, formatting, and annotation-selected codecs are
unsupported.
+
+### Naming strategy
+
+```java
+ForyJson json =
+ ForyJson.builder()
+ .withPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
+ .build();
+```
+
+The default `LOWER_CAMEL_CASE` preserves the discovered Java logical property
name. `SNAKE_CASE`
+maps `userName` to `user_name`, `URLValue` to `url_value`, and `version2FA` to
`version2_fa`.
+Explicit `JsonProperty` names, parameter-local creator names, and subtype
discriminator properties
+bypass the strategy.
+
+### `JsonIgnore`
+
+`JsonIgnore` is field-targeted and controls both directions of the complete
logical property:
+
+```java
+@JsonIgnore(ignoreRead = false, ignoreWrite = true)
+private String serverManagedValue;
+```
+
+Both flags default to true. Accessors cannot restore an ignored direction, and
`JsonProperty`
+cannot override it. Fory core's `Expose` has no effect in Fory JSON.
+
+### `JsonCreator`
+
+The compact mode lists existing Java logical property names in parameter order
and reuses their
+normalized metadata:
+
+```java
+public final class User {
+ public final long id;
+ public final String name;
+
+ @JsonCreator({"id", "name"})
+ public User(long id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+}
+```
+
+Parameter-local mode gives every parameter an explicit JSON name and permits
creator-only inputs:
+
+```java
+@JsonCreator
+public static User create(
+ @JsonProperty("user_id") long id,
+ @JsonProperty("display_name") String name) {
+ return new User(id, name);
+}
+```
+
+The modes cannot be mixed. Compact names must be non-empty and unique, their
count must match the
+parameter count, and compact parameters cannot also declare `JsonProperty`.
Parameter-local mode
+requires a non-empty, unique `JsonProperty` name on every parameter. The
creator is the complete
+read schema and setters do not run after it.
+
+Exactly one creator is allowed. It must be public, have at least one
parameter, and be neither
+varargs nor generic. A factory is also static, declares the target class as
its exact return type,
+and returns a non-null value whose runtime class is exactly the target.
Missing references use null,
+missing primitives use zero, duplicate members use the last value, and
explicit primitive null
+fails. Records cannot declare `JsonCreator`.
+
+### `JsonSubTypes`
+
+`JsonSubTypes` defines a complete finite table on an interface or abstract
base. Each entry has a
+case-sensitive logical name and exactly one Java source: a class literal or
trusted binary
+`className`. JSON never supplies class names or expands the table.
+
+Default property inclusion:
+
+```java
+@JsonSubTypes(
+ property = "kind",
+ value = {
+ @JsonSubTypes.Type(value = Circle.class, name = "circle"),
+ @JsonSubTypes.Type(
+ className = "com.example.shape.Rectangle",
+ name = "rectangle")
+ })
+public interface Shape {}
+```
+
+```json
+{ "kind": "circle", "radius": 2 }
+```
+
+The discriminator is emitted first but may appear at any direct input member
position. It must
+occur exactly once, contain a known String name, and not collide with a
subtype property.
+
+Wrapper object:
+
+```java
+@JsonSubTypes(
+ inclusion = JsonSubTypes.Inclusion.WRAPPER_OBJECT,
+ value = {@JsonSubTypes.Type(value = Circle.class, name = "circle")})
+public interface Shape {}
+```
+
+```json
+{ "circle": { "radius": 2 } }
+```
+
+Wrapper array:
+
+```java
+@JsonSubTypes(
+ inclusion = JsonSubTypes.Inclusion.WRAPPER_ARRAY,
+ value = {@JsonSubTypes.Type(value = Circle.class, name = "circle")})
+public interface Shape {}
+```
+
+```json
+["circle", { "radius": 2 }]
+```
+
+| Inclusion | `property` | Value rule
|
+| ---------------- | ---------------------- |
----------------------------------- |
+| `PROPERTY` | Required and non-empty | Ordinary subtype object members
|
+| `WRAPPER_OBJECT` | Must be empty | Complete subtype value
|
+| `WRAPPER_ARRAY` | Must be empty | Complete subtype value as
element 1 |
+
+Wrapper inclusions support exact custom subtype codecs. Logical names and
resolved concrete,
+assignable classes must each be unique. Only exact listed runtime classes are
accepted; listing a
+parent does not admit descendants. The annotation is read from the declared
base itself and is not
+inherited from another annotated base. Null is plain JSON null unless a custom
codec on the
+declared base replaces the annotation. Readers accept only the configured
shape, so changing
+inclusion is a wire-format change. At GraalVM native-image runtime, use class
literals instead of
+`className`.
+
+## Custom codecs
+
+An exact custom codec replaces the complete mapping for its registered class
and owns null:
+
+```java
+import java.math.BigDecimal;
+import org.apache.fory.json.codec.JsonCodec;
+import org.apache.fory.json.reader.Latin1JsonReader;
+import org.apache.fory.json.reader.Utf16JsonReader;
+import org.apache.fory.json.reader.Utf8JsonReader;
+import org.apache.fory.json.writer.StringJsonWriter;
+import org.apache.fory.json.writer.Utf8JsonWriter;
+
+public final class MoneyCodec implements JsonCodec<Money> {
+ @Override
+ public void writeString(StringJsonWriter writer, Money value) {
+ if (value == null) {
+ writer.writeNull();
+ } else {
+ writer.writeBigDecimal(value.amount);
+ }
+ }
+
+ @Override
+ public void writeUtf8(Utf8JsonWriter writer, Money value) {
+ if (value == null) {
+ writer.writeNull();
+ } else {
+ writer.writeBigDecimal(value.amount);
+ }
+ }
+
+ @Override
+ public Money readLatin1(Latin1JsonReader reader) {
+ return reader.tryReadNullToken() ? null : new
Money(reader.readBigDecimal());
+ }
+
+ @Override
+ public Money readUtf16(Utf16JsonReader reader) {
+ return reader.tryReadNullToken() ? null : new
Money(reader.readBigDecimal());
+ }
+
+ @Override
+ public Money readUtf8(Utf8JsonReader reader) {
+ return reader.tryReadNullToken() ? null : new
Money(reader.readBigDecimal());
+ }
+}
+
+final class Money {
+ final BigDecimal amount;
+
+ Money(BigDecimal amount) {
+ this.amount = amount;
+ }
+}
+```
+
+Register it once:
+
+```java
+import org.apache.fory.json.ForyJson;
+
+ForyJson json =
+ ForyJson.builder()
+ .registerCodec(Money.class, new MoneyCodec())
+ .build();
+```
+
+The parent property still controls its name, ignore direction, and inclusion
before the codec runs.
+The codec instance is shared concurrently and must be thread-safe. A custom
codec on a subtype is
+compatible with wrapper inclusion, not inline property inclusion. A codec on
the base replaces its
+`JsonSubTypes` annotation.
+
+## Type validation and untrusted input
+
+Fory JSON always applies its fixed disallow list. Add an application policy
with:
+
+```java
+ForyJson json =
+ ForyJson.builder()
+ .withTypeChecker(
+ (className, context) ->
+ className.startsWith("com.example.model.")
+ || className.equals("java.util.List")
+ || className.equals("java.util.Map"))
+ .build();
+```
+
+Allow every application model and non-built-in container type that the
declared schema uses. The
+checker applies while application types are prepared for serialization and
parsing and must be
+thread-safe. Built-in scalars normally skip the custom checker. Custom codecs
cannot bypass the
+fixed disallow list.
+
+`withClassLoader` fixes subtype `className` resolution. Otherwise `build()`
snapshots the thread
+context class loader and falls back to the Fory JSON loader.
+
+`maxDepth` is not an input-size or memory quota. Enforce request size,
timeout, and resource limits
+at the transport boundary. `Class`, `URL`, `InetAddress`, and
`InetSocketAddress` are unsupported by
+default. URL and arbitrary unsupported Number/CharSequence subclasses require
exact custom codecs.
+
+## Limits and unsupported features
+
+- No shared-reference identity or circular-reference protocol. Use Fory binary
when needed.
+- No open polymorphism, JSON class-name IDs, subtype discovery, or runtime
subtype-table extension.
+- No InputStream parser, incremental `OutputStream` writer on the `ForyJson`
root API, or
+ pretty-print configuration.
+- No Jackson/Gson annotation compatibility.
+- No aliases, views, filters, injection, managed/back references, object
identity annotations, root
+ wrapping, format annotations, or annotation-driven raw JSON values.
+- Fory core's `Expose` is ignored.
+
+Circular graphs eventually fail `maxDepth`; they are not reconstructed.
+
+## Errors and troubleshooting
+
+| Symptom | Action
|
+| ---------------------------------- |
-----------------------------------------------------------------------------------------------
|
+| `ForyJsonException` | Check JSON grammar, target type,
mapping support, depth, trailing content, or output cause |
+| `InsecureException` | Check Fory's disallow list and the
configured type checker |
+| Builder `IllegalArgumentException` | Use positive depth, concurrency, and
retained-buffer values |
+| Declared write fails | Remove wildcard/type variables and pass
an assignable value; primitive declarations reject null |
+| Immutable value is empty | Use a record, valid creator, or custom
codec |
+| Ordinary object cannot be created | Add a usable no-argument constructor,
use a record or creator, or register a codec |
+| Accessor annotation fails | Use an eligible public JavaBean
accessor and disable field mode |
+| Subtype fails | Write with the declared base, list the
exact runtime class, and use the configured wire shape |
+| Collection fails | Target a supported interface/common
implementation or register a codec |
+
+Creator failures other than `Error` are wrapped with their original cause.
User codec code may
+still throw its own runtime exceptions.
+
+## Related Java guides
+
+- [Java serialization overview](index.md)
+- [Native binary serialization](native-serialization.md)
+- [Xlang binary serialization](xlang-serialization.md)
+- [Java configuration](configuration.md)
+- [Troubleshooting](troubleshooting.md)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]