Skip to main content

3. Loading and Usage

With our @Config definitions built, MittenLib has generated the implementation, validation, and loading logic. The final step is to integrate this into your application.

Integrating with Guice

As mentioned before, to load a configuration automatically, your DTO must declare a @Source:

@Config
@Source("config.yml") // Tells MittenLib this config maps to a specific file
public interface AdvancedConfig {
// ...
}

When @Source is present, the processor automatically creates a Guice module named ConfigLoaderModule that binds your config to a me.bristermitten.mittenlib.config.provider.ConfigProvider that automatically reads, deserializes, and validates the config. We can now inject this config anywhere in our plugin!

package me.bristermitten.mittenlib.docs.tutorial;

import com.google.inject.Guice;
import com.google.inject.Injector;
import me.bristermitten.mittenlib.MittenLib;
// Assuming this is generated in your package:
// import com.yourplugin.config.ConfigLoaderModule;
import org.bukkit.plugin.java.JavaPlugin;

public class PluginInitExample extends JavaPlugin {
@Override
public void onEnable() {
MittenLib<PluginInitExample> mittenLib = MittenLib.withDefaults(this)
// Register the generated config module which binds all your configs
.config(new ConfigLoaderModule());

Injector injector = mittenLib.setup();

// Get your class that depends on the ConfigProvider
UsageExample example = injector.getInstance(UsageExample.class);
example.doSomething();
}
}

What happens here?

  1. MittenLib.withDefaults(this) sets up the default loaders (YAML, JSON), formatters, and path resolvers relative to your plugin's data folder.

  2. config(new ConfigLoaderModule()) registers the module generated by the annotation processor. This single module automatically binds all your @Config implementations, deserializers, and validators into the Guice context.

  3. MittenLib reads config.yml, parses it, validates it against your constraints, and binds the resulting AdvancedConfig instance to the Guice container.

Using the Configuration

Once bound, you can inject your configuration anywhere in your application using ConfigProvider<T>.

package me.bristermitten.mittenlib.docs.tutorial;

import com.google.inject.Inject;
import me.bristermitten.mittenlib.config.provider.ConfigProvider;

public class UsageExample {
private final ConfigProvider<AdvancedConfig> configProvider;

@Inject
public UsageExample(ConfigProvider<AdvancedConfig> configProvider) {
this.configProvider = configProvider;
}

public void doSomething() {
// Retrieve the currently loaded config
AdvancedConfig config = configProvider.get();

System.out.println("Connecting to " + config.host() + ":" + config.port());

// Nested configs are just method calls
String dbUser = config.database().username();
System.out.println("Database user: " + dbUser);
}
}

Why ConfigProvider<T>?

You inject a ConfigProvider instead of the raw AdvancedConfig instance. This allows for dynamic reloading. Rather than needing an explicit reload command, the ConfigProvider will always yield the most up-to-date, newly validated instance of the config when get() is called, without needing to recreate your dependent classes!

You can still inject the normal values if this reloading functionality is not desired.

Success!

In very little code, we're able to load and validate a complex config file, and access it from anywhere in our application, with automatic reloading!

To find out more about this system, check out the Config Reference.