modules.md

August 14, 2026 ยท View on GitHub

ForyJsonModule packages a coherent set of Fory JSON registrations into one reusable extension. A module can be provided by a language integration, a third-party library, a framework, or an application. Use a module when consumers should install the whole extension with one builder call; use direct builder registration for an application-specific codec that does not need separate distribution.

Creating and Installing a Module

After implementing a codec such as MoneyCodec from the Custom Codecs guide, a library can distribute its registration as a module:

import org.apache.fory.json.ForyJson;
import org.apache.fory.json.ForyJsonModule;
import org.apache.fory.json.ModuleContext;

public final class MoneyJsonModule implements ForyJsonModule {
  public static final MoneyJsonModule INSTANCE = new MoneyJsonModule();

  private MoneyJsonModule() {}

  @Override
  public void install(ModuleContext context) {
    context.registerCodec(Money.class, new MoneyCodec());
  }
}

ForyJson json =
    ForyJson.builder()
        .withModule(MoneyJsonModule.INSTANCE)
        .build();

Installation runs while build() creates the immutable runtime configuration. Treat a module configuration as immutable after adding it to a builder. Registered codec instances are shared by concurrent operations and must be thread-safe.

Module Registrations

ModuleContext exposes the registrations needed by reusable integrations:

RegistrationUse
registerCodec(Class, JsonValueCodec)One shared complete codec for an exact class
registerCodec(Class, JsonCodecFactory)A resolver-owned complete codec for an exact class
registerMixin(Class)An annotated Mixin for its declared target
registerCodecFactory(JsonCodecFactory)A codec family selected from a parameterized target type

Codec implementations and JsonCodecFactory behavior are documented in Custom Codecs. Modules only package those registrations for installation.

Application registrations made directly on ForyJsonBuilder take precedence over module exact registrations. Conflicting module registrations fail during build() instead of depending on installation order.

Module Identity

moduleKey() identifies the module configuration for generated-code reuse and conflict checking. The default key is the module class name and is sufficient for a configuration-free module.

A configurable module must return a deterministic key that includes every option affecting codec selection or generated code. Do not include secrets, mutable process state, or values unrelated to the installed JSON behavior.

public final class ConfiguredJsonModule implements ForyJsonModule {
  private final boolean compactNames;

  public ConfiguredJsonModule(boolean compactNames) {
    this.compactNames = compactNames;
  }

  @Override
  public String moduleKey() {
    return getClass().getName() + ":compactNames=" + compactNames;
  }

  @Override
  public void install(ModuleContext context) {
    // Register the codecs, factories, or Mixins selected by this configuration.
  }
}

For a Scala example that packages derived third-party enum codecs in a module, see Packaging Derived Codecs in a Module.