Quarkus Fory

Integrates with the Apache Fory serialization framework. Apache Fory is a blazingly fast multi-language serialization framework powered by JIT and zero-copy. With the quarkus-fory extension, users can use fast and easy-to-use serialization feature provided by Apache Fory out-of-box.

Installation

If you want to use this extension, you need to add the io.quarkiverse.fory:quarkus-fory extension first to your build file.

For instance, with Maven, add the following dependency to your POM file:

<dependency>
    <groupId>io.quarkiverse.fory</groupId>
    <artifactId>quarkus-fory</artifactId>
    <version>1.4.0</version>
</dependency>

Usage

If you want to use Apache Fory to serialize your objects, you need to use @Inject to get an instance of Fory to serialize your objects. Fory instance is created by quarkus-fory at build time, you don’t need to create Fory by yourself. And you also need to mark your classes for serialization.

For instance, the following code is an example using @Inject and @ForySerialization annotation to serialize a JDK 17+ record object.

import java.util.List;
import java.util.Map;

import io.quarkiverse.fory.ForySerialization;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

import org.apache.fory.BaseFory;

@ForySerialization
record Foo(int f1, String f2, List<String> f3, Map<String, Long> f4) {
}

@Path("/fory")
@ApplicationScoped
public class ForyResources {
  @Inject
  BaseFory fory;

  @GET
  @Path("/record")
  public Boolean testSerializeFooRecord() {
    Foo foo1 = new Foo(10, "abc", List.of("str1", "str2"), Map.of("k1", 10L, "k2", 20L));
    Foo foo2 = (Foo) fory.deserialize(fory.serialize(foo1));
    return foo1.equals(foo2);
  }
}

You can also mark a class for serialization by application.properties configurations.

quarkus.fory.register-class-names=io.demo.Foo,io.demo.Bar

If you want to specify class id or serializer for a class, you can do it by annotation:

import io.quarkiverse.fory.ForySerialization;

@ForySerialization(classId = 200, serializer = FooSerializer.class)
record Foo(int f1, String f2, List<String> f3, Map<String, Long> f4) {
}

If the class is a third-party class which you can’t add annotation, you can specify the targetClasses property:

import io.quarkiverse.fory.ForySerialization;

@ForySerialization(classId = 200, serializer = FooSerializer.class, targetClasses = Foo.class)
public class FooConfig {
}

Or you can configure by application.properties configurations.

quarkus.fory.register-class."io.demo.Foo".class-id=200
quarkus.fory.register-class."io.demo.Foo".serializer=io.demo.FooSerializer

For about how to create a customized Fory serializer for a class, see Apache Fory document

Integartion in Quarkus REST/RESTEasy

It enables efficient and structured data exchange between client and server using the fory during serialization and deserialization with application/fory media type. Example for a JAX-RS endpoint on the server side like:

@Path("/example")
@Produces("application/fory")
@Consumes("application/fory")
public class ExampleResource {
    @POST
    public Foo test(Foo obj) {
       return new Foo(1, "test");
    }
}
If class registration is enabled, the class ID (or serialization identifier) must be identical on both the client and server sides. A mismatch in the class ID will result in serialization or deserialization issues, potentially causing runtime errors or data corruption. If class registration is disabled, please do not assign class id at client and server slides.

JSON Serialization

The extension also supports application/json media type via Fory JSON — a high-performance JSON serializer built on the same Fory engine. Use standard @Produces and @Consumes annotations with APPLICATION_JSON:

import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

record Foo(int f1, String f2) {
}

@Path("/example")
public class ExampleResource {
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Foo get() {
        return new Foo(1, "test");
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Foo post(Foo obj) {
        return new Foo(obj.f1() + 1, obj.f2());
    }
}

Unlike the binary format, Fory JSON needs no class registration: @ForySerialization is not required, and any supported Java type can be serialized. Clients receive standard JSON output consumable by browsers, CLI tools, and any JSON-compliant client.

In native mode, types that are not registered through @ForySerialization fall back to runtime codec generation, which GraalVM forbids, and requests for them fail with UnsupportedFeatureError: Classes cannot be defined at runtime. Annotate the types you serialize as JSON when you target native image.

Fory JSON support is disabled by default, because it takes over the application/json media type and would conflict with other JSON extensions such as Jackson or JSON-B. It also requires the fory-json artifact, which is an optional dependency of the extension so that applications not using JSON don’t ship it.

To enable it, add the dependency — using the same version as the fory-core brought in by the extension:

<dependency>
    <groupId>org.apache.fory</groupId>
    <artifactId>fory-json</artifactId>
    <version>${fory.version}</version>
</dependency>

and turn it on:

quarkus.fory.json.enabled=true

If the property is enabled without fory-json on the classpath, the build fails with an explicit message.

Extension Configuration Reference

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

The language of fory. The default is JAVA.

Environment variable: QUARKUS_FORY_LANGUAGE

java, xlang

java

Require class registration for serialization. The default is true.

Environment variable: QUARKUS_FORY_REQUIRED_CLASS_REGISTRATION

boolean

true

Whether track shared or circular references.

Environment variable: QUARKUS_FORY_TRACK_REF

boolean

false

Set class schema compatible mode.
SCHEMA_CONSISTENT: Class schema must be consistent between serialization peer and deserialization peer.
COMPATIBLE: Class schema can be different between serialization peer and deserialization peer. They can add/delete fields independently.

Environment variable: QUARKUS_FORY_COMPATIBLE_MODE

schema-consistent, compatible

schema-consistent

Use variable length encoding for int/long.

Environment variable: QUARKUS_FORY_COMPRESS_NUMBER

boolean

true

Whether compress string for small size.

Environment variable: QUARKUS_FORY_COMPRESS_STRING

boolean

true

Whether deserialize/skip data of un-existed class. If not enabled, an exception will be thrown if class not exist.

Environment variable: QUARKUS_FORY_DESERIALIZE_NONEXISTENT_CLASS

boolean

false

If an enum value doesn’t exist, return a null instead of throws exception.

Environment variable: QUARKUS_FORY_DESERIALIZE_NONEXISTENT_ENUM_VALUE_AS_NULL

boolean

false

Whether to use thread safe fory. The default is true.

Environment variable: QUARKUS_FORY_THREAD_SAFE

boolean

true

Names of classes to register which no need to be with class-id or customize serializer. It has to be separated by comma.

Environment variable: QUARKUS_FORY_REGISTER_CLASS_NAMES

string

Configurations of register class

Type

Default

Class id must be greater or equal to 256, and it must be different between classes. The default is -1.

Environment variable: QUARKUS_FORY_REGISTER_CLASS__REGISTER_CLASS_NAME__CLASS_ID

int

-1

Specify a customized serializer for current class. This should be empty to let Fory create serializer for current class. But if users want to customize serialization for this class, one can provide serializer here.

Environment variable: QUARKUS_FORY_REGISTER_CLASS__REGISTER_CLASS_NAME__SERIALIZER

string

Whether Fory JSON support is enabled. Disabled by default. When enabled, the extension registers a JSON MessageBodyReader/Writer backed by Fory JSON for the application/json media type, which conflicts with other JSON extensions such as Jackson or JSON-B.

Environment variable: QUARKUS_FORY_JSON_ENABLED

boolean

false