Skip to content

Using Adventure SPI to provide plugin-classloader-specific MiniMessage implementation #732

@TheMeinerLP

Description

@TheMeinerLP

Description

Adventure’s SPI system provides powerful extension capabilities that are highly valuable for advanced developers building platforms, middleware, or framework-style plugins. However, practical documentation and real-world examples of SPI usage—especially for MiniMessage providers—are currently limited.

This issue proposes adding a small documentation section demonstrating how a plugin can provide its own MiniMessage.Provider via SPI, enabling controlled customization within a plugin classloader without affecting global behavior.

Real-world example:
https://github.com/OneLiteFeatherNET/Titan/blob/201b087b9e031e41b9fcc917146cfd9803917aaf/common/src/main/java/net/onelitefeather/titan/common/utils/component/TitanMiniMessageImpl.java


Why documenting this would help

Documenting this pattern would:

  • Help advanced developers understand how Adventure can be extended safely via SPI
  • Provide clarity on plugin-classloader-scoped MiniMessage customization
  • Reduce confusion around global vs classloader-local MiniMessage behavior
  • Prevent misuse of static/global MiniMessage instances
  • Encourage consistent and safe integration with Adventure

Many framework-style plugins and shared libraries benefit from having a controlled MiniMessage entry point, but this capability is currently mostly discovered by reading source code rather than official documentation.


What could be added (minimal scope)

A short documentation section could include:

1. Basic SPI registration

META-INF/services/net.kyori.adventure.text.minimessage.MiniMessage$Provider

2. Minimal example provider

public final class ExampleMiniMessageProvider implements MiniMessage.Provider {
    private static final MiniMessage INSTANCE = MiniMessage.builder()
        .tags(TagResolver.builder()
        .resolver(TagResolver.standard())
        .resolver(Placeholder.component("prefix", name ->
            Component.text("[Example] ")
        ))
        .build())
    .build();

    @Override
    public MiniMessage miniMessage() {
        return INSTANCE;
    }
}

3. Optional: Custom placeholder example

MiniMessage.builder()
    .tags(TagResolver.builder()
        .resolver(TagResolver.standard())
        .resolver(Placeholder.component("prefix", name ->
            Component.text("[Example] ")
        ))
        .build())
    .build();

Why this matters for the ecosystem

Documenting SPI-based MiniMessage providers would make it easier for experienced developers to:

  • Build framework-style plugins with consistent text handling
  • Safely customize MiniMessage behavior per plugin/classloader
  • Avoid global side effects or cross-plugin conflicts
  • Integrate Adventure more deeply without modifying core behavior

The SPI system is a powerful part of Adventure’s architecture, and a small documentation addition would make this capability more visible and easier to use correctly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    dev guideThis issue or PR aims to introduce developer API documentationmeta guideThis issue or PR aims to introduce in-depth ways to work with codeproject: Adventure

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions