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]