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

commit fb7a0bcb37513d79b27440f20ba67c9eee2d50b7
Author: chaokunyang <[email protected]>
AuthorDate: Thu Jul 16 12:13:04 2026 +0000

    🔄 synced local 'docs/guide/' with remote 'docs/guide/'
---
 docs/guide/java/android-support.md |  49 +++++++++++++---
 docs/guide/java/graalvm-support.md |  52 +++++++++++++++--
 docs/guide/java/json-support.md    | 115 +++++++++++++++++++++++++++++++++----
 3 files changed, 191 insertions(+), 25 deletions(-)

diff --git a/docs/guide/java/android-support.md 
b/docs/guide/java/android-support.md
index 25421b25ea..0a45194ae5 100644
--- a/docs/guide/java/android-support.md
+++ b/docs/guide/java/android-support.md
@@ -100,6 +100,40 @@ public final class Invoice {
 }
 ```
 
+The same processor supports Fory JSON Mixins. A Mixin declares one exact 
target and is registered
+on the runtime that should use it:
+
+```java
+import org.apache.fory.json.ForyJson;
+import org.apache.fory.json.annotation.JsonBase64;
+import org.apache.fory.json.annotation.JsonMixin;
+
+@JsonMixin(target = ThirdPartyInvoice.class)
+public abstract class ThirdPartyInvoiceMixin {
+  @JsonBase64 byte[] signature;
+}
+
+ForyJson json =
+    ForyJson.builder().registerMixin(ThirdPartyInvoiceMixin.class).build();
+```
+
+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
+produces no generated output.
+
+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
+target's direct companion.
+
+Only one source is enabled for an exact target in one built runtime. 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
+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
@@ -137,13 +171,14 @@ supports mutable classes, creator-backed classes, and 
Records through their norm
 construction paths. When the containing model and its unwrapped children use 
`JsonType`, their
 generated companions supply those operations.
 
-Android-desugared Records require a direct `@JsonType` annotation and the 
annotation processor.
-Manual R8 rules alone cannot reconstruct Record component order because 
Android does not provide
-the Java Record reflection APIs. This also applies to a Record whose complete 
representation is a
-`JsonValue` String: the generated companion identifies the propagated 
component accessor and calls
-an annotated one-String canonical constructor directly. Generated child codecs 
act on one level
-exactly as they do on the JVM. Every Record in a `JsonUnwrapped` path needs 
its own direct
-`JsonType`. Use a complete value codec for deeper nested behavior.
+Android-desugared Records require processor-generated operations from either a 
direct `@JsonType`
+declaration or a compiled exact `@JsonMixin` pair. Manual R8 rules alone 
cannot reconstruct Record
+component order because Android does not provide the Java Record reflection 
APIs. This also applies
+to a Record whose complete representation is a `JsonValue` String: the 
generated companion
+identifies the propagated component accessor and calls an annotated one-String 
canonical
+constructor directly. Generated child codecs act on one level exactly as they 
do on the JVM. Every
+Record in a `JsonUnwrapped` path needs its own direct `JsonType` declaration 
or compiled exact
+`JsonMixin` pair. Use a complete value codec for deeper nested behavior.
 
 ## Static Generated Serializers
 
diff --git a/docs/guide/java/graalvm-support.md 
b/docs/guide/java/graalvm-support.md
index 553f616f45..7da3e7a2a4 100644
--- a/docs/guide/java/graalvm-support.md
+++ b/docs/guide/java/graalvm-support.md
@@ -80,6 +80,43 @@ public class JsonExample {
 }
 ```
 
+The processor also supports Fory JSON Mixins for models that cannot be 
modified:
+
+```java
+import org.apache.fory.json.ForyJson;
+import org.apache.fory.json.annotation.JsonMixin;
+import org.apache.fory.json.annotation.JsonProperty;
+
+@JsonMixin(target = ThirdPartyUser.class)
+public abstract class ThirdPartyUserMixin {
+  @JsonProperty("user_id")
+  long id;
+}
+
+public class JsonExample {
+  public static void main(String[] args) {
+    ForyJson json =
+        ForyJson.builder().registerMixin(ThirdPartyUserMixin.class).build();
+    ThirdPartyUser user = json.fromJson("{\"user_id\":1}", 
ThirdPartyUser.class);
+    System.out.println(json.toJson(user));
+  }
+}
+```
+
+`JsonMixin` is a build-time entry point for its exact declared target, so the 
target does not need
+`JsonType` solely to use the Mixin. The registered Mixin class literal must be 
reachable from the
+application. The processor emits available target operations for each 
non-empty Mixin, and the
+Fory JSON Native Image Feature retains the effective runtime metadata. Normal 
runtime codec
+precedence still selects the representation. An empty Mixin produces no 
generated output.
+
+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
+built with. If the target also has a direct `JsonType` companion, a non-empty 
registered Mixin
+selects the pair-specific artifact instead of combining the overlay with the 
direct companion.
+
+Do not add application reflection configuration as a replacement for the 
generated configuration.
+The native executable resolves the same effective annotations as the JVM.
+
 The processor generates direct property and creator operations. The 
`fory-json` artifact activates
 its Native Image Feature automatically and retains the generated factories and 
required model
 metadata. `@JsonType` is not inherited, so annotate every concrete runtime 
model. An annotated base
@@ -106,17 +143,20 @@ on the JVM and Android.
 `JsonValue` fields and effective public zero-argument methods are supported, 
including matching
 one-String `JsonCreator` constructors and public static factories. Fixed 
`JsonRawValue` fields and
 getters support trusted raw String values, and fixed `JsonBase64` fields and 
getters support Base64
-`byte[]` values as on the JVM. Annotate each reachable owning model with 
`JsonType` so Native Image
-retains these members and the Base64 codec constructor. A directly annotated 
`JsonValue` Record
-uses its generated component accessor and canonical constructor operations.
+`byte[]` values as on the JVM. For direct target annotations, annotate each 
reachable owning model
+with `JsonType` so Native Image retains these members and the Base64 codec 
constructor. A directly
+annotated `JsonValue` Record uses its generated component accessor and 
canonical constructor
+operations. An effective declaration supplied by a Mixin uses the Mixin 
workflow above instead.
 
 `JsonAnyProperty` and `JsonAnyGetter` flatten their Map into the enclosing 
object. Use
 `@JsonCodec(valueCodec = ...)` on that field or getter to customize each 
dynamic value. A second
 `JsonAnySetter` parameter may use the normal configuration for its own value 
shape.
 
-`JsonUnwrapped` uses the same interpreted behavior as on the JVM. Annotate the 
containing model and
-every unwrapped child or intermediate object with `JsonType` so each model 
receives its generated
-property and creator operations.
+`JsonUnwrapped` uses the same interpreted behavior as on the JVM. For direct 
target annotations,
+annotate the containing model and every unwrapped child or intermediate object 
with `JsonType` so
+each model receives its generated property and creator operations. A Mixin 
retains the
+unwrapped models reached by its effective schema; register a separate exact 
Mixin for a child only
+when that child's annotations also need an overlay.
 
 Child codecs act on one direct level. `elementCodec` supports `Collection`, 
Java arrays, and
 `AtomicReferenceArray`; `contentCodec` supports `Optional` and 
`AtomicReference`; `keyCodec` and
diff --git a/docs/guide/java/json-support.md b/docs/guide/java/json-support.md
index 042320821e..6d3dbfe447 100644
--- a/docs/guide/java/json-support.md
+++ b/docs/guide/java/json-support.md
@@ -295,6 +295,7 @@ are rejected.
 | `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                       |
+| `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
@@ -309,8 +310,9 @@ disabled. Every other builder option keeps the behavior 
described above.
 
 Fory JSON provides `JsonProperty`, `JsonPropertyOrder`, `JsonIgnore`, 
`JsonAnyProperty`,
 `JsonAnyGetter`, `JsonAnySetter`, `JsonCreator`, `JsonCodec`, `JsonValue`, 
`JsonRawValue`,
-`JsonBase64`, `JsonUnwrapped`, `JsonSubTypes`, and `JsonType` under
-`org.apache.fory.json.annotation`. They are not Jackson, Gson, or Fory 
binary-protocol annotations.
+`JsonBase64`, `JsonUnwrapped`, and `JsonSubTypes` as mapping 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.
 
 ```java
 import java.util.LinkedHashMap;
@@ -323,6 +325,8 @@ import org.apache.fory.json.annotation.JsonBase64;
 import org.apache.fory.json.annotation.JsonCodec;
 import org.apache.fory.json.annotation.JsonCreator;
 import org.apache.fory.json.annotation.JsonIgnore;
+import org.apache.fory.json.annotation.JsonMixin;
+import org.apache.fory.json.annotation.JsonMixinRemove;
 import org.apache.fory.json.annotation.JsonProperty;
 import org.apache.fory.json.annotation.JsonPropertyOrder;
 import org.apache.fory.json.annotation.JsonRawValue;
@@ -342,6 +346,92 @@ to receive a companion. See
 A directly annotated model that uses the default object codec requires that 
generated companion;
 the runtime reports a configuration error if the processor output is missing.
 
+### Mixins
+
+Use a Mixin to configure an existing class without changing its source:
+
+```java
+import org.apache.fory.json.ForyJson;
+import org.apache.fory.json.annotation.JsonMixin;
+import org.apache.fory.json.annotation.JsonProperty;
+import org.apache.fory.json.annotation.JsonUnwrapped;
+
+@JsonMixin(target = ThirdPartyUser.class)
+abstract class ThirdPartyUserMixin {
+  @JsonProperty("user_id")
+  long id;
+
+  @JsonUnwrapped(prefix = "address_")
+  Address address;
+}
+
+ForyJson json = 
ForyJson.builder().registerMixin(ThirdPartyUserMixin.class).build();
+```
+
+The source must be a named abstract class or interface, must not be local or 
anonymous, must not
+extend or implement another type, and is never instantiated. An annotated 
source field, method,
+constructor, or parameter selects an existing target declaration by its Java 
signature. The source
+cannot invent a Java field, method, constructor, generic type, subtype 
implementation, or executable
+body. It may assign supported JSON roles such as property, creator, factory, 
subtype table, or value
+representation to matching declarations that already exist on the target. 
Every Java type, access
+operation, invocation, and runtime value still comes from the target.
+
+Registration is exact-target only. A base-class registration does not change a 
subclass, and an
+interface registration does not change an implementation. A subclass Mixin may 
select a member
+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`,
+`JsonAnySetter`, `JsonBase64`, `JsonCodec`, `JsonCreator`, `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.
+
+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
+inheriting values from the target annotation. Other annotation types on that 
target declaration
+remain effective.
+
+Use `JsonMixinRemove` to make selected target annotations ineffective:
+
+```java
+import org.apache.fory.json.annotation.JsonMixin;
+import org.apache.fory.json.annotation.JsonMixinRemove;
+import org.apache.fory.json.annotation.JsonRawValue;
+
+@JsonMixin(target = ThirdPartyMessage.class)
+abstract class QuotedMessageMixin {
+  @JsonMixinRemove(JsonRawValue.class)
+  String body;
+}
+```
+
+Removal affects only the matched declaration in the exact-target 
configuration. Removing
+`JsonRawValue` restores ordinary quoted String output; removing `JsonBase64` 
restores the ordinary
+`byte[]` representation; removing `JsonUnwrapped` restores a nested object 
property. Type-level
+removal can mask inherited `JsonCodec` or `JsonPropertyOrder` declarations for 
the exact target.
+Removing an absent annotation is harmless, but the selector must still match 
exactly one target
+declaration. A source cannot both declare and remove the same annotation type 
on one declaration.
+
+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.
+
+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
+Mixin codec, while a type-level Mixin codec wins over the built-in mapping for 
that target.
+
+Records use their existing field, accessor, and canonical-constructor 
parameter declarations. A
+Mixin does not introduce a separate record-component model. Use source 
selectors for those real
+declarations and keep repeated annotations consistent as required by normal 
record property
+mapping.
+
+On Android and GraalVM Native Image, compile non-empty Mixin sources with the 
Fory annotation
+processor so required generated operations and platform configuration are 
available. See
+[Android Support](android-support.md) and [GraalVM 
Support](graalvm-support.md).
+
 ### `JsonProperty`
 
 An annotation on a field, getter, or setter configures the complete merged 
logical property:
@@ -1026,13 +1116,13 @@ The first `JsonAnySetter` parameter is the String 
property name. Its second para
 
 Fory resolves each current value in this order:
 
-| Priority | Source                                    |
-| -------: | ----------------------------------------- |
-|        1 | Current property or parameter `JsonCodec` |
-|        2 | Exact `registerCodec` registration        |
-|        3 | Direct type `JsonCodec` declaration       |
-|        4 | Inherited type declaration                |
-|        5 | Built-in or default JSON mapping          |
+| Priority | Source                                            |
+| -------: | ------------------------------------------------- |
+|        1 | Current property or parameter `JsonCodec`         |
+|        2 | Exact `registerCodec` registration                |
+|        3 | Exact-target type `JsonCodec` after Mixin overlay |
+|        4 | Inherited-frontier type `JsonCodec` declaration   |
+|        5 | Built-in or default JSON mapping                  |
 
 One logical property may expose the annotation from its field, getter, setter 
parameter, creator
 parameter, or record propagation. Repeated configurations must be identical; 
Fory does not merge
@@ -1059,9 +1149,10 @@ type-declaration codec is used for a more specific 
target, every decoded value m
 assignable to that target.
 
 The annotation has the same FIELD, METHOD, and PARAMETER behavior on the JVM, 
Android, and GraalVM
-Native Image. Ordinary Android classes may omit `JsonType` and provide 
equivalent exact rules;
-Android-desugared Records, including `JsonValue` Records, require `JsonType` 
and the processor.
-GraalVM object models follow the `JsonType` workflow in
+Native Image. Ordinary Android classes may omit `JsonType` and provide 
equivalent exact rules.
+Android-desugared Records, including `JsonValue` Records, require 
processor-generated operations
+from either a direct `JsonType` declaration or a compiled exact `JsonMixin` 
pair. GraalVM object
+models follow the build-time workflow in
 [GraalVM Support](graalvm-support.md).
 
 ## Type validation and untrusted input


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

Reply via email to