Skip to content

weftkit runs your Bukkit plugin's lifecycle

weftkit manages your plugin's lifecycle at runtime and resolves the wiring that drives it at compile time, so the dependency graph that survives javac is the one that runs on the server.

Get started Browse the examples

Four classes make a plugin that welcomes joining players and greets anyone who runs /hello. Components declare their dependencies as constructor parameters, and weftkit builds them, injects them, and registers the listener and the command. No registerEvents, no setExecutor, no factories, no reflection.

@Registry
public final class HelloPlugin extends WeftPlugin {

    @Override
    protected ComponentRegistry registry() {
        return WeftWiring.INSTANCE;
    }
}

The only wiring you write: hand back the registry weftkit generates.

@Wired
@Singleton
final class Greeter {

    public String greet(CommandSender who) {
        return "Welcome, " + who.getName();
    }
}

A plain singleton. weftkit builds it and injects it wherever it is asked for.

@Wired
@Singleton
final class JoinListener implements Listener {

    private final Greeter greeter;

    JoinListener(Greeter greeter) {
        this.greeter = greeter;
    }

    @EventHandler
    public void onJoin(PlayerJoinEvent event) {
        event.getPlayer().sendMessage(greeter.greet(event.getPlayer()));
    }
}

Registered for you. Its dependency arrives through the constructor.

@Wired
@Singleton
@CommandHandler("hello")
final class HelloCommand implements CommandExecutor {

    private final Greeter greeter;

    HelloCommand(Greeter greeter) {
        this.greeter = greeter;
    }

    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
        sender.sendMessage(greeter.greet(sender));
        return true;
    }
}

@CommandHandler binds it to the hello entry in plugin.yml. The same Greeter, injected again.

And when the wiring is wrong

The processor validates the whole dependency graph as it compiles. Forget an annotation, introduce a cycle, or depend on something nothing provides, and the build stops with a message pointing at the offending class, long before a server ever loads the jar.

$ ./gradlew build

JoinListener.java:9: error: Dependency must be @Wired or a @Provides product: com.example.hello.Greeter
    JoinListener(Greeter greeter) {
                 ^
1 error

Troubleshooting lists every error the processor can raise and how to fix it.

See your plugin's structure

Dependency graph of the player-homes example: the amber HomeCommand and SetHomeCommand singletons point at the HomeStore singleton, which points at the dashed package-private HomesFile, while the teal MetricsModule points at WeftMetricsSettingsDefaults and the teal ListenerModule and CommandModule stand alone.

The processor also renders the whole dependency graph as Graphviz. Every component and every edge, package-private classes included. This is the player-homes example.

What you get

  • Managed lifecycle


    Components load in dependency order, run startup and teardown hooks, and shut down cleanly in reverse.

  • Bukkit integration


    onEnable, onDisable, listener registration, and shutdown are handled for you on any Bukkit server.

  • Modules and feature flags


    Features ship as modules that discover their content by enumeration, and flags toggle whole components off.

  • Internals stay internal


    Package-private classes are wired like any other component, so injection never forces your internals public.

Why weftkit

A general purpose container hands you an object graph and stops there. weftkit is built around the plugin lifecycle instead: load order, startup and teardown hooks, and clean shutdown in reverse are first-class, and listener and command registration on any Bukkit server, Spigot to Paper, comes with them. That is the part Dagger and Guice leave for you to wire by hand. If you are weighing options, see how weftkit compares to Dagger, Guice, and wiring by hand.

Pre-release

weftkit is pre-1.0, so the public API can still change between releases until 1.0.

Add it to your build

weftkit is published to Maven Central. One dependency carries the runtime and annotations; the two annotation processors validate the graph and generate the registry as you compile.

dependencies {
    implementation("org.weftkit:weftkit-bukkit:0.6.0")
    annotationProcessor("org.weftkit:weftkit-processor:0.6.0")
    annotationProcessor("org.weftkit:weftkit-bukkit-processor:0.6.0")
}

The full build, including the Bukkit API dependency and repositories, is in getting started.

Learn from complete plugins

The examples are complete runnable plugins, each documented class by class with the source embedded.

  • join-leave-messages


    The smallest useful plugin: one wired listener, one injected component, three classes total.

  • player-homes


    The lifecycle end to end: load homes from disk at startup, abort on corrupt data, save on shutdown.

  • announcer


    A module that discovers its content through enumeration, with settings and a feature flagged component.

FAQ

What is weftkit?

weftkit is a lifecycle and dependency injection framework for Bukkit, Spigot, and Paper Minecraft plugins. It starts your components in dependency order, runs their startup and teardown hooks, and registers your listeners, with the wiring resolved and validated at compile time so mistakes fail the build instead of the server.

How does weftkit compare to Dagger and Guice?

Like Dagger, weftkit resolves the dependency graph at compile time with zero runtime reflection. Unlike Dagger or Guice, it also manages the plugin lifecycle: load order, teardown, and Bukkit listener registration are built in rather than left to you. The comparison page has an honest side by side, including wiring by hand.

Which servers and Java versions does it support?

Any Bukkit-based server, from CraftBukkit and Spigot to Paper and its forks, on Java 17 or newer. weftkit depends only on the Bukkit API, not on server internals or NMS.

Is weftkit production-ready?

weftkit is pre-1.0, so the public API can still change between releases. The runtime itself is exercised in production: SilkSpawners, the plugin weftkit was extracted from, runs on it.

Is weftkit free to use?

Yes. weftkit is open source under the Apache License 2.0, free for commercial and private plugins alike. The source, issue tracker, and releases live on GitHub, and the license is bundled in every published jar.

Why is it called weftkit?

A weft is the horizontal thread passed back and forth through the vertical warp threads in weaving, binding the loose strands into a single fabric. That is what weftkit does: it threads through your independent components and binds them into one plugin with a single, managed lifecycle.

Ready to wire your plugin?

Add one dependency, hand back the generated registry, and let the build catch the mistakes.