跳到主要内容
版本:dev

快速开始

要求与安装​

Fory JSON 在标准 JDK、GraalVM Native Image 和 Android 上支持 Java 8 及更高版本。 Java record 需要 Java 17 或更高版本。

已发布的 Fory JSON 制品可从 Maven Central 获取,开发快照可从 Apache 快照仓库获取。以下仓库声明同时支持两者。所有 Fory 模块应使用依赖坐标中显示的同一版本。

Maven:

<repositories>
<repository>
<id>apache-snapshots</id>
<url>https://repository.apache.org/snapshots/</url>
<releases><enabled>false</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</repository>
</repositories>

<dependency>
<groupId>org.apache.fory</groupId>
<artifactId>fory-json</artifactId>
<version>1.7.7</version>
</dependency>

Gradle:

repositories {
maven("https://repository.apache.org/snapshots/") {
mavenContent { snapshotsOnly() }
}
mavenCentral()
}

implementation("org.apache.fory:fory-json:1.7.7")

Kotlin​

Kotlin/JVM 应用添加可选的 Kotlin JSON 运行时,并使用其统一 builder 入口:

build.gradle.kts
dependencies {
implementation("org.apache.fory:fory-json-kotlin:1.7.7")
}
import org.apache.fory.json.kotlin.ForyJsonKotlin
import org.apache.fory.json.kotlin.jsonTypeRef

data class User(val id: Long, val name: String)

val json = ForyJsonKotlin.builder().build()
val userType = jsonTypeRef<User>()
val text = json.toJson(User(7, "Alice"), userType)
val decoded = json.fromJson(text, userType)

Kotlin 模块不需要 kotlin-reflect。在 Android 上,启用 R8 或 ProGuard 时,或 Kotlin 源码中的 Mixin 为 Java sealed 目标添加推导式 JsonSubTypes 时,请添加 fory-json-kotlin-ksp。后一种情况还需要 fory-annotation-processor 和 JDK 17 或更新版本。GraalVM Native Image 使用常规 @ForyJsonProvider 流程。完整设置和 Kotlin 类型行为见 Kotlin JSON 指南。

JDK 25 及更高版本​

在 JDK 25 及更高版本中,需要向 Fory core 开放 java.lang.invoke。对于 classpath 应用:

--add-opens=java.base/java.lang.invoke=ALL-UNNAMED

对于 module-path 应用:

--add-opens=java.base/java.lang.invoke=org.apache.fory.core

Fory JSON 的 Java Platform Module System(JPMS)模块名为 org.apache.fory.json,Kotlin 集成模块名为 org.apache.fory.json.kotlin。

快速上手​

创建一个 ForyJson 实例并重复使用。该实例线程安全,无需关闭。

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);
}
}

未知输入属性默认会被跳过,除非由启用读取的 Any 字段或 any-setter 接收。 对象中的 null 属性默认省略。默认 JSON 属性发现顺序不属于兼容性契约;如果必须明确输出属性顺序, 请使用 JsonPropertyOrder 或 JsonProperty.index。

读写 API​

Fory JSON 支持 String 输入/输出、UTF-8 字节输入/输出,以及通过 ByteBuffer 分块提供的增量 UTF-8 输入。目前不提供阻塞式 InputStream 解析 API。

操作运行时类型声明的 Class声明的 TypeRef
String 输出toJson(value)toJson(value, type)toJson(value, typeRef)
UTF-8 字节toJsonBytes(value)toJsonBytes(value, type)toJsonBytes(value, typeRef)
UTF-8 OutputStreamwriteJsonTo(value, out)writeJsonTo(value, type, out)writeJsonTo(value, typeRef, out)
String 输入-fromJson(text, type)fromJson(text, typeRef)
UTF-8 输入-fromJson(bytes, type)fromJson(bytes, typeRef)
UTF-8 字节范围-fromJson(bytes, offset, length, type)fromJson(bytes, offset, length, typeRef)

每次 fromJson 调用恰好消费一个 JSON 值,并拒绝其后的非空白内容。字节范围重载只解析指定范围,忽略范围之前和之后的字节。返回的 String 和字节数组与内部可复用缓冲区相互独立。

writeJsonTo 会缓冲完整的 UTF-8 文档,只执行一次 OutputStream.write,既不 flush 也不关闭 调用方拥有的流。它是便捷输出 API,并非增量式 JSON 流式写入。I/O 失败会包装为 ForyJsonException。

增量 JSON 流​

JsonStreamDecoder 可增量解码一个顶层 JSON 数组中的元素,或换行分隔的 JSON(NDJSON)记录。输入可以是任意边界的 UTF-8 ByteBuffer 分块;提供下一个分块之前,必须消费完当前分块:

import java.nio.ByteBuffer;
import org.apache.fory.json.ForyJson;
import org.apache.fory.json.JsonStreamDecoder;

ForyJson json = ForyJson.builder().build();
JsonStreamDecoder<User> decoder =
json.newArrayStreamDecoder(User.class, 64 * 1024 * 1024);

for (ByteBuffer chunk : chunks) {
while (decoder.decodeNext(chunk)) {
User user = decoder.value();
consume(user);
}
}
decoder.finish();

对于以 LF 或 CRLF 分隔的记录,使用 newNdjsonStreamDecoder。最后一条 NDJSON 记录可以没有行结束符;finish() 解码出该记录时返回 true:

JsonStreamDecoder<User> decoder =
json.newNdjsonStreamDecoder(User.class, 64 * 1024 * 1024);

for (ByteBuffer chunk : chunks) {
while (decoder.decodeNext(chunk)) {
consume(decoder.value());
}
}
if (decoder.finish()) {
consume(decoder.value());
}

每次 decodeNext 调用最多返回一个值。返回 true 后,如果缓冲区仍有剩余字节,应继续传入同一缓冲区;返回 false 则表示该缓冲区已被消费至 limit。返回 true 且 value() == null 表示 JSON null。

解码器推进传入缓冲区的 position,但不保留该缓冲区,也不改变其 limit 或字节序。支持堆缓冲区、直接缓冲区、切片和只读缓冲区。每个解码器只负责一个流,不具备线程安全性,并且在 finish() 或失败后不能复用。必需的 maxValueBytes 限制分别应用于每个数组元素或每条 NDJSON 记录,而不是整个流。对于数组,不计外层方括号、逗号和元素前跳过的空白,但计入元素后、逗号或右方括号前的空白。对于 NDJSON,除 LF 或 CRLF 行结束符外的每个字节都计入限制。纯空白行会被跳过,但超出限制的纯空白行仍会失败。

泛型类型​

根类型包含泛型参数时,请使用 TypeRef:

import java.util.List;
import org.apache.fory.json.ForyJson;
import org.apache.fory.reflect.TypeRef;

ForyJson json = ForyJson.builder().build();
TypeRef<List<User>> usersType = new TypeRef<List<User>>() {};

List<User> users = json.fromJson("[{\"id\":7,\"name\":\"Alice\"}]", usersType);
String encoded = json.toJson(users, usersType);

使用声明类型写入时,类型必须完全绑定;通配符和类型变量会被拒绝。非 null 值必须可赋给声明的原始类型。

声明的 Schema 控制序列化。例如,声明为具体父类的属性使用父类映射属性,不会自动加入仅子类拥有的字段。 声明为 Object 的值在写入时使用运行时分派,在读取时使用自然 JSON 映射。

声明类型与多态​

不带类型的写入重载根据运行时类分派。基类拥有 JsonSubTypes 元数据时,请使用声明类型重载:

Shape shape = new Circle(2);

json.toJson(shape); // Circle's concrete representation
json.toJson(shape, Shape.class); // Shape's configured subtype representation
json.toJsonBytes(shape, Shape.class);
json.writeJsonTo(shape, Shape.class, outputStream);

对于包含多态值的容器,请通过 TypeRef 携带声明的基类类型:

TypeRef<List<Shape>> shapesType = new TypeRef<List<Shape>>() {};
String encoded = json.toJson(shapes, shapesType);