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 b935368481 🔄 synced local 'docs/guide/' with remote 'docs/guide/'
b935368481 is described below

commit b935368481a822a2bac5010bf1db9b6654239dfc
Author: chaokunyang <[email protected]>
AuthorDate: Mon Aug 3 09:44:17 2026 +0000

    🔄 synced local 'docs/guide/' with remote 'docs/guide/'
---
 docs/guide/java/android-support.md |  46 ++++++++++-----
 docs/guide/java/configuration.md   |  11 ++--
 docs/guide/java/graalvm-support.md |  26 ++++++++-
 docs/guide/java/json-support.md    | 117 +++++++++++++++++++++++++++++++------
 4 files changed, 158 insertions(+), 42 deletions(-)

diff --git a/docs/guide/java/android-support.md 
b/docs/guide/java/android-support.md
index 9a6ff8be32..bbb0448f58 100644
--- a/docs/guide/java/android-support.md
+++ b/docs/guide/java/android-support.md
@@ -82,8 +82,8 @@ Child codecs act on one direct level only. For example, 
`elementCodec` on `Money
 `value` codec when deeper custom behavior is required.
 
 Add the annotation processor and mark application object models with 
`JsonType` to generate direct
-field, getter, setter, Record constructor, and `JsonCreator` operations 
together with exact R8
-rules:
+field, getter, setter, Record constructor, `JsonCreator`, and `JsonValidator` 
operations together
+with exact R8 rules:
 
 ```kotlin
 dependencies {
@@ -93,10 +93,18 @@ dependencies {
 
 ```java
 import org.apache.fory.json.annotation.JsonType;
+import org.apache.fory.json.annotation.JsonValidator;
 
 @JsonType
 public final class Invoice {
-  // ...
+  public long total;
+
+  @JsonValidator
+  public void validate() {
+    if (total < 0) {
+      throw new IllegalArgumentException("total must not be negative");
+    }
+  }
 }
 ```
 
@@ -122,6 +130,10 @@ R8 rules and any pair-specific target operations that the 
runtime can use. Regis
 effective type codecs, and built-in mappings keep their normal runtime 
precedence. An empty Mixin
 produces no generated output.
 
+A Mixin may place `JsonValidator` on a public abstract zero-argument `void` 
method that exactly
+matches a public target method. The generated pair calls that target method 
directly. The target
+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
 pair-specific companion for a non-empty registered Mixin instead of combining 
the overlay with the
@@ -134,11 +146,12 @@ only the last registered source.
 
 Use the processor-generated R8 rules for non-empty Mixins instead of broad 
package keep rules.
 
-Ordinary non-Record classes that omit `JsonType` can supply equivalent exact 
rules themselves.
-Retain every model
-constructor, field, method, generic signature, declaration annotation, and 
parameter annotation used
-by Fory JSON, plus the public no-argument constructor of every 
annotation-selected codec. For the
-previous `Invoice` example:
+Ordinary non-Record classes that omit `JsonType` can supply equivalent exact 
rules themselves unless
+they declare `JsonValidator`. Direct validators require the 
processor-generated calls from
+`JsonType`; do not replace them with reflection rules. Retain every model 
constructor, field,
+method, generic signature, declaration annotation, and parameter annotation 
used by Fory JSON,
+plus the public no-argument constructor of every annotation-selected codec. 
For a model without a
+validator:
 
 ```proguard
 -keepattributes 
Signature,RuntimeVisibleAnnotations,RuntimeVisibleParameterAnnotations
@@ -156,14 +169,15 @@ previous `Invoice` example:
 The same exact-rule approach supports every `JsonCodec` member; it is not 
limited to complete-value
 codecs. `JsonType` is not required for codec selection on an ordinary class.
 
-For `@JsonType` models, the generated R8 rules also retain `JsonValue` fields 
and effective methods,
-fixed `JsonRawValue` and `JsonBase64` fields and getters, `JsonFormat` 
date/time fields, their runtime
-annotations, and the Base64 codec constructor. Without `@JsonType`, these 
annotations still work
-through reflection, but a release-minified application must keep the exact 
annotated members,
-annotation attributes, and codec constructor itself. A `JsonValue` method may 
use a non-JavaBean
-name, so its manual rule must name that method explicitly. `JsonFormat` keeps 
the same direct-field
-and one-wrapper-level behavior as on the JVM, including `timezone` for 
`Instant`, `ZonedDateTime`,
-and `OffsetDateTime`.
+For `@JsonType` models, generated operations and R8 rules also cover effective 
`JsonValidator`
+methods, `JsonValue` fields and effective methods, fixed `JsonRawValue` and 
`JsonBase64` fields and
+getters, `JsonFormat` date/time fields, their runtime annotations, and the 
Base64 codec constructor.
+Without `@JsonType`, the value, raw, Base64, format, and codec annotations 
still work through
+reflection, but a release-minified application must keep the exact annotated 
members, annotation
+attributes, and codec constructor itself. A `JsonValue` method may use a 
non-JavaBean name, so its
+manual rule must name that method explicitly. `JsonFormat` keeps the same 
direct-field and
+one-wrapper-level behavior as on the JVM, including `timezone` for `Instant`, 
`ZonedDateTime`, and
+`OffsetDateTime`.
 
 Android Fory JSON requires a retained no-argument constructor for an ordinary 
mutable class; it may
 be non-public when Android reflection can make it accessible. `JsonCreator` 
constructor-backed
diff --git a/docs/guide/java/configuration.md b/docs/guide/java/configuration.md
index ba59f6ba78..0f1f44ae81 100644
--- a/docs/guide/java/configuration.md
+++ b/docs/guide/java/configuration.md
@@ -103,11 +103,12 @@ Security-related options:
 - `withMaxDepth(...)` rejects unexpectedly deep object graphs.
 - `withMaxGraphMemoryBytes(...)` sets an approximate gate for materialized 
graph memory during one
   root deserialization. The estimate mainly covers collections, maps, arrays, 
structs, and objects;
-  it skips leaf values such as strings, binary data, primitive scalars, and 
dense primitive arrays.
-  Actual process memory can be higher than this limit. 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 is a fixed `128 MiB`; set a positive 
byte limit when trusted
-  workloads need a larger or smaller gate.
+  Fory core primitive arrays and primitive lists count their primitive storage 
from the decoded
+  length. It skips leaf values such as strings, primitive scalars, and 
dedicated binary values that
+  do not use a primitive-array serializer. Actual process memory can be higher 
than this limit. 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 is a fixed 
`128 MiB`; set a
+  positive byte limit when trusted workloads need a larger or smaller gate.
 - `withMaxUnbackedContainerItems(...)` limits count-driven collection and map 
work whose repeated
   read bodies do not consume proportional input. The default is `8192`; zero 
is a strict limit.
 - `withMaxTypeFields(...)` and `withMaxTypeMetaBytes(...)` bound the field 
count
diff --git a/docs/guide/java/graalvm-support.md 
b/docs/guide/java/graalvm-support.md
index 088ffed80e..3c667dc136 100644
--- a/docs/guide/java/graalvm-support.md
+++ b/docs/guide/java/graalvm-support.md
@@ -52,11 +52,19 @@ Fory JSON has its own Native Image Feature and does not use 
the Fory annotation
 ```java
 import org.apache.fory.json.ForyJson;
 import org.apache.fory.json.annotation.JsonType;
+import org.apache.fory.json.annotation.JsonValidator;
 
 @JsonType
 public final class User {
   public long id;
   public String name;
+
+  @JsonValidator
+  public void validate() {
+    if (id < 0) {
+      throw new IllegalArgumentException("id must not be negative");
+    }
+  }
 }
 
 public class JsonExample {
@@ -150,11 +158,23 @@ built with.
 
 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
-`@JsonSubTypes` table registers its listed subtypes automatically. Reachable 
concrete `Collection`
-and `Map` root types are supported when they have the public no-argument 
constructor required by
-Fory JSON. A class referenced only by a runtime string is not reachable;
+`@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;
 `JsonSubTypes.Type.className` is therefore unsupported in a native image.
 
+Do not add application reflection configuration as a replacement for the 
generated configuration.
+The native executable resolves the same effective annotations as the JVM.
+
+Effective `JsonValidator` methods must be public instance methods with no 
arguments and a `void`
+return type. A model with a directly declared validator must use `JsonType`. A 
validator contributed
+by a registered Mixin uses that exact Mixin-target pair, so the target does 
not also need
+`JsonType`. The Native Image Feature prepares validator access for interpreted 
configurations and
+provider-generated codecs invoke the same effective validators. Do not add 
reflection configuration
+for validators. Complete custom codecs, complete `JsonValue` representations, 
and creators that
+enforce validation themselves perform their own validation.
+
 Type, field, effective ordinary getter, setter value parameter, and 
`JsonCreator` parameter
 `@JsonCodec` annotations are supported. The Feature retains every selected 
complete-value, element,
 content, Map-key, and Map-value codec constructor. This is the same annotation 
model used on the
diff --git a/docs/guide/java/json-support.md b/docs/guide/java/json-support.md
index 2e5e8533c4..96fb5357e5 100644
--- a/docs/guide/java/json-support.md
+++ b/docs/guide/java/json-support.md
@@ -289,16 +289,17 @@ are rejected.
 | `withClassLoader`            | Snapshotted context loader, then Fory loader 
| Resolve annotation subtype class names                 |
 | `maxDepth`                   | `20`                                         
| Maximum nested object/array depth                      |
 | `withMaxCachedFieldNames`    | `DEFAULT_MAX_CACHED_FIELD_NAMES` (`8192`)    
| Field-name cache entries per reader; zero disables it  |
+| `withMaxGraphMemoryBytes`    | `DEFAULT_MAX_GRAPH_MEMORY_BYTES` (128 MiB)   
| Approximate retained graph limit for each root read    |
 | `withConcurrencyLevel`       | `max(1, 2 * processors)`                     
| Maximum concurrent root operations                     |
 | `withBufferSizeLimitBytes`   | 2 MiB                                        
| Reusable capacity retained by each pooled writer       |
 | `registerCodec`              | None                                         
| Exact-class complete-value codec                       |
 | `registerMixin`              | None                                         
| Annotation Mixin for its exact declared target         |
 | `withTypeChecker`            | None                                         
| Application policy in addition to Fory's disallow list |
 
-Depth, concurrency, and retained buffer limits must be positive. The 
cached-field-name limit applies
-independently to each reader; zero disables the cache, and the setting does 
not limit accepted
-input. The buffer setting does not limit output size. Builder changes after 
`build()` do not mutate
-an existing runtime.
+Depth, graph-memory, concurrency, and retained buffer limits must be positive. 
The
+cached-field-name limit applies independently to each reader; zero disables 
the cache, and the
+setting does not limit accepted input. The buffer setting does not limit 
output size. Builder
+changes after `build()` do not mutate an existing runtime.
 
 In a GraalVM native image, runtime compilation and asynchronous compilation 
are unavailable.
 Configurations returned by a reachable `ForyJsonProvider` use codecs generated 
while the image is
@@ -309,7 +310,8 @@ other builder option keeps the behavior described above.
 
 Fory JSON provides `JsonProperty`, `JsonPropertyOrder`, `JsonIgnore`, 
`JsonAnyProperty`,
 `JsonAnyGetter`, `JsonAnySetter`, `JsonCreator`, `JsonCodec`, `JsonValue`, 
`JsonRawValue`,
-`JsonBase64`, `JsonFormat`, `JsonUnwrapped`, and `JsonSubTypes` as mapping 
annotations under
+`JsonBase64`, `JsonFormat`, `JsonUnwrapped`, `JsonSubTypes`, and 
`JsonValidator` as mapping and
+validation annotations under
 `org.apache.fory.json.annotation`. `JsonType` is a separate build-time 
generation marker. They are
 not Jackson, Gson, or Fory binary-protocol annotations.
 
@@ -332,6 +334,7 @@ import org.apache.fory.json.annotation.JsonPropertyOrder;
 import org.apache.fory.json.annotation.JsonRawValue;
 import org.apache.fory.json.annotation.JsonSubTypes;
 import org.apache.fory.json.annotation.JsonType;
+import org.apache.fory.json.annotation.JsonValidator;
 import org.apache.fory.json.annotation.JsonValue;
 import org.apache.fory.json.annotation.JsonUnwrapped;
 ```
@@ -383,10 +386,11 @@ interface registration does not change an implementation. 
A subclass Mixin may s
 that the subclass inherits, but the resulting annotation applies only while 
that exact subclass is
 mapped.
 
-All Fory JSON mapping annotations are supported: `JsonAnyGetter`, 
`JsonAnyProperty`,
+All Fory JSON mapping and validation annotations are supported: 
`JsonAnyGetter`, `JsonAnyProperty`,
 `JsonAnySetter`, `JsonBase64`, `JsonCodec`, `JsonCreator`, `JsonFormat`, 
`JsonIgnore`, `JsonProperty`,
-`JsonPropertyOrder`, `JsonRawValue`, `JsonSubTypes`, `JsonUnwrapped`, and 
`JsonValue`. `JsonType`
-cannot be added or removed because it controls build-time generation rather 
than the JSON schema.
+`JsonPropertyOrder`, `JsonRawValue`, `JsonSubTypes`, `JsonUnwrapped`, 
`JsonValidator`, and
+`JsonValue`. `JsonType` cannot be added or removed because it controls 
build-time generation rather
+than the JSON schema.
 
 A source annotation replaces the target annotation of the same type on the 
matched declaration.
 The complete annotation is replaced, so omitted members use their declared 
defaults instead of
@@ -418,9 +422,9 @@ declaration. A source cannot both declare and remove the 
same annotation type on
 Only one source is enabled for an exact target in a built runtime. Registering 
a different source
 for the same target replaces the earlier registration, while registering the 
same source again is
 idempotent. `build()` snapshots the current last-registration-wins mapping; a 
later registration on
-the builder does not change a previously built `ForyJson`. A source with no 
mapping annotations is
-a no-op; registering it after another source for the same target clears the 
earlier overlay for
-subsequent builds.
+the builder does not change a previously built `ForyJson`. A source with no 
mapping or validation
+annotations is a no-op; registering it after another source for the same 
target clears the earlier
+overlay for subsequent builds.
 
 A `JsonCodec` supplied by a Mixin is the target's effective annotation and 
follows the ordinary
 codec precedence below. In particular, an exact `registerCodec` registration 
wins over a type-level
@@ -883,6 +887,55 @@ missing primitives use zero, duplicate members use the 
last value, and explicit
 fails. Records cannot declare a property-based `JsonCreator`; a record with 
`JsonValue` may annotate
 its one-String canonical constructor for the value form.
 
+### `JsonValidator`
+
+Use `JsonValidator` to run application validation after an object is 
completely constructed and
+populated:
+
+```java
+public final class Account {
+  public String id;
+  public long balance;
+
+  @JsonValidator
+  public void validate() {
+    if (id == null || id.isEmpty() || balance < 0) {
+      throw new IllegalArgumentException("invalid account");
+    }
+  }
+}
+```
+
+A validator must be a public concrete instance method with no arguments and a 
`void` return type.
+Every effective validator runs exactly once after its object is complete, 
including creator-built
+objects, records, nested and unwrapped objects, and selected subtypes. JSON 
null skips validation.
+Multiple validators have no guaranteed order, and the first failure stops 
validation. `Error` is
+propagated; other invocation failures become `ForyJsonException` with the 
original cause.
+`JsonValidator` has no index or ordering member. A `JsonCreator` may instead 
enforce the invariant
+during construction.
+
+A Mixin can add a validator to a matching public target method:
+
+```java
+@JsonMixin(target = ThirdPartyAccount.class)
+abstract class ThirdPartyAccountMixin {
+  @JsonValidator
+  public abstract void checkValid();
+}
+```
+
+The Mixin method must match the target method's exact name, parameters, and 
return type. Use
+`@JsonMixinRemove(JsonValidator.class)` on a matching source method to remove 
the target annotation
+for that configuration. An unannotated override does not inherit the 
overridden method's
+validator.
+
+Validation applies to the default object mapping. A complete codec selected 
through
+`registerCodec` or a type-level `JsonCodec`, and a complete `JsonValue` 
representation, performs
+its own validation. On Android, compile direct validator models with 
`JsonType` and the Fory
+annotation processor; a Mixin validator uses the generated exact Mixin-target 
pair. GraalVM Native
+Image discovers a direct `JsonType` or registered Mixin and prepares its 
effective validators
+without annotation-processor output.
+
 ### `JsonSubTypes`
 
 `JsonSubTypes` defines a complete finite table on an interface or abstract 
base. Each entry has a
@@ -1014,6 +1067,14 @@ concurrently and must be thread-safe. A custom codec on 
a subtype is compatible
 inclusion, not inline property inclusion. A codec on the base replaces its 
`JsonSubTypes`
 annotation.
 
+A custom codec that materializes composite graph owners must call 
`JsonReader.reserveGraphMemory`
+with an application-defined byte estimate before creating each owner. This 
applies to composite
+application objects, collections, maps, and reference arrays. Reserve 
collection and map reference
+storage before the mutation that may grow it. A custom scalar or other 
dedicated leaf
+representation, such as `MoneyCodec` above, needs no reservation. Complete 
codecs also run any
+required application validation themselves; Fory JSON does not wrap a complete 
custom
+representation with the target type's `JsonValidator` methods.
+
 ### Selecting codecs with `JsonCodec`
 
 Use `@JsonCodec` on a class, record, enum, or interface to declare its default 
complete-value
@@ -1226,9 +1287,29 @@ 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.
+`maxDepth` is not an input-size or memory quota. `withMaxGraphMemoryBytes` 
separately limits the
+approximate retained graph created by each root read and defaults to a fixed 
128 MiB. Every String
+or UTF-8 byte-array root starts with the full configured limit, including 
after a prior success or
+failure.
+
+The graph budget includes shallow POJO and record storage, collections and 
sets plus candidate
+element-reference slots, maps plus candidate key/value-reference slots, 
reference arrays plus their
+slots, and Java primitive arrays plus their primitive storage. Natural 
`JsonObject` and `JsonArray`
+values use the same rules. Repeated set elements and duplicate or overwritten 
map members consume
+candidate-slot budget for every occurrence. Dedicated leaves are excluded: 
null, strings,
+characters, booleans, numbers including big numbers, enums, temporal and other 
scalar values, and
+binary values. A `byte[]` decoded from a JSON numeric array counts as a 
primitive array, while a
+`byte[]` handled by a binary or Base64 codec remains a binary leaf. A 
reference array still counts
+when its elements are leaves, and an object still counts when all properties 
are leaves.
+`AtomicReference`, `AtomicReferenceArray`, and generic `Optional<T>` values 
include wrapper and
+reference storage; primitive optionals and atomic primitive values are leaves.
+
+This is a portable approximate estimate, not exact JVM heap accounting. 
Custom-codec allocations
+that the codec does not reserve, application constructor or validator work, 
temporary parsing
+storage, and other process memory can exceed the limit. 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
 
@@ -1247,9 +1328,9 @@ Circular graphs eventually fail `maxDepth`; they are not 
reconstructed.
 
 | Symptom                            | Action                                  
                                                        |
 | ---------------------------------- | 
-----------------------------------------------------------------------------------------------
 |
-| `ForyJsonException`                | Check JSON grammar, target type, 
mapping support, depth, trailing content, or output cause      |
+| `ForyJsonException`                | Check grammar, target type, mapping, 
depth, graph memory, validation, trailing input, or output |
 | `InsecureException`                | Check Fory's disallow list and the 
configured type checker                                      |
-| Builder `IllegalArgumentException` | Check the configured depth, 
concurrency, retained-buffer, and cached-field-name limits          |
+| Builder `IllegalArgumentException` | Check depth, graph-memory, concurrency, 
retained-buffer, and cached-field-name limits           |
 | 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                                                    |
 | `JsonValue` read fails             | Add one plain `String` creator, or 
register an exact custom codec                               |
@@ -1261,8 +1342,8 @@ Circular graphs eventually fail `maxDepth`; they are not 
reconstructed.
 | 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.
+Creator and validator failures other than `Error` are wrapped with their 
original cause. User codec
+code may still throw its own runtime exceptions.
 
 ## Related Java guides
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to