### Example Configuration File Content Source: https://github.com/exlll/configlib/blob/master/README.md A sample YAML content for a configuration file, showing how values are represented. This is used in conjunction with the 'update' method example. ```yaml i: 20 k: 30 ``` -------------------------------- ### Example Configuration Type Source: https://github.com/exlll/configlib/blob/master/README.md A simple Java class annotated with @Configuration, used to demonstrate the behavior of the 'update' method when a configuration file exists. ```java @Configuration public final class C { int i = 10; int j = 11; } ``` -------------------------------- ### Annotate Configuration Class (Java) Source: https://github.com/exlll/configlib/wiki/Tutorial Annotates a final class with @Configuration to mark it as a configuration class. This is the starting point for defining configurations. ```java @Configuration public final class GameConfig {} ``` -------------------------------- ### Java Recursive Type Definitions Example Source: https://github.com/exlll/configlib/blob/master/README.md Demonstrates direct and indirect recursive type definitions in Java, which are not currently supported by ConfigLib. Avoid using these patterns to prevent type mismatches. ```java public final class RecursiveTypDefinitions { // Direct recursive definition @Configuration static final class R { R r; } // Indirect recursive definition @Configuration static final class R1 { R2 r2; } @Configuration static final class R2 { R1 r1; } } ``` -------------------------------- ### Nesting Examples for Collection Element Serialization Source: https://github.com/exlll/configlib/blob/master/README.md Illustrates different nesting levels for applying serializers to elements within nested collections like Lists and Sets. Incorrect nesting values can lead to serialization errors. ```java // MyListSerializer is applied to 'list' @SerializeWith(serializer = MyListSerializer.class) List> list; ``` ```java // MySetSerializer is applied to the Set elements of 'list' @SerializeWith(serializer = MySetSerializer.class, nesting = 1) List> list; ``` ```java // MyStringSerializer is applied to the strings within the set elements of 'list' @SerializeWith(serializer = MyStringSerializer.class, nesting = 2) List> list; ``` ```java // MyMap0Serializer is applied to 'map' @SerializeWith(serializer = MyMap0Serializer.class) Map> map; ``` ```java // MyMap1Serializer is applied to the Map values of 'map' @SerializeWith(serializer = MyMap1Serializer.class, nesting = 1) Map> map; ``` ```java // MyDoubleSerializer is applied to the doubles within the nested values of 'map' @SerializeWith(serializer = MyDoubleSerializer.class, nesting = 2) Map> map; ``` -------------------------------- ### Implement Custom Java Serializer for Point Source: https://github.com/exlll/configlib/blob/master/README.md Example of a custom serializer for java.awt.Point, converting it to and from a string format. Ensure your serializer converts to and from valid target types. ```java public final class PointSerializer implements Serializer { @Override public String serialize(Point element) { return element.x + ":" + element.y; } @Override public Point deserialize(String element) { String[] parts = element.split(":"); int x = Integer.parseInt(parts[0]); int y = Integer.parseInt(parts[1]); return new Point(x, y); } } ``` -------------------------------- ### Custom Serializer with SerializerContext Constructor Source: https://github.com/exlll/configlib/blob/master/README.md Example of a custom serializer that accepts a SerializerContext via its constructor. This is required when using the @SerializeWith annotation. ```java public final class PointSerializer implements Serializer { private final SerializerContext context; public PointSerializer(SerializerContext context) { this.context = context; } // implementation ... ``` -------------------------------- ### Define Game Play Period (Java) Source: https://github.com/exlll/configlib/wiki/Tutorial Defines the start and end dates for the game's allowed play period using LocalDate objects. This sets the valid timeframe for the game. ```java @Configuration public final class GameConfig { // ... private LocalDate startDate = LocalDate.of(2022, Month.JANUARY, 1); private LocalDate endDate = LocalDate.of(2022, Month.DECEMBER, 31); } ``` -------------------------------- ### Import ConfigLib via Jitpack (Maven) Source: https://github.com/exlll/configlib/blob/master/README.md Configure your Maven project with the Jitpack repository and add the ConfigLib dependency. ```xml jitpack.io https://jitpack.io com.github.Exlll.ConfigLib configlib-yaml v4.8.1 ``` -------------------------------- ### Import ConfigLib via Jitpack (Gradle Groovy) Source: https://github.com/exlll/configlib/blob/master/README.md Configure your Gradle project with the Jitpack repository and add the ConfigLib dependency using Groovy syntax. ```groovy repositories { maven { url 'https://jitpack.io' } } dependencies { implementation 'com.github.Exlll.ConfigLib:configlib-yaml:v4.8.1' } ``` -------------------------------- ### Create and Use YamlConfigurationStore Source: https://github.com/exlll/configlib/blob/master/README.md Instantiate YamlConfigurationStore for direct saving, loading, or updating of configurations. This is more efficient for multiple operations. ```java YamlConfigurationProperties properties = YamlConfigurationProperties.newBuilder().build(); YamlConfigurationStore store = new YamlConfigurationStore<>(Config.class, properties); Config config1 = store.load(configurationFile); store.save(config1, configurationFile); Config config2 = store.update(configurationFile); ``` -------------------------------- ### Import ConfigLib via Jitpack (Gradle Kotlin) Source: https://github.com/exlll/configlib/blob/master/README.md Configure your Gradle project with the Jitpack repository and add the ConfigLib dependency using Kotlin syntax. ```kotlin repositories { maven { url = uri("https://jitpack.io") } } dependencies { implementation("com.github.Exlll.ConfigLib:configlib-yaml:v4.8.1") } ``` -------------------------------- ### Import ConfigLib via GitHub Packages (Maven) Source: https://github.com/exlll/configlib/blob/master/README.md Configure your Maven project with the GitHub Packages repository and add the ConfigLib dependency. ```xml de.exlll https://maven.pkg.github.com/Exlll/ConfigLib de.exlll configlib-yaml 4.8.1 ``` -------------------------------- ### Load Configuration using YamlConfigurations Source: https://github.com/exlll/configlib/blob/master/README.md Use static methods from YamlConfigurations for loading configurations. Overloads allow specifying properties or a builder for advanced configuration. ```java Config config1 = YamlConfigurations.load(configurationFile, Config.class); YamlConfigurations.save(configurationFile, Config.class, config1); Config config2 = YamlConfigurations.update(configurationFile, Config.class); ``` ```java YamlConfigurationProperties properties = YamlConfigurationProperties.newBuilder().build(); Config config1 = YamlConfigurations.load(configurationFile, Config.class, properties); ``` ```java Config config2 = YamlConfigurations.load( configurationFile, Config.class, builder -> builder.inputNulls(true).outputNulls(false) ); ``` -------------------------------- ### Basic Configuration Class Source: https://github.com/exlll/configlib/blob/master/README.md Define a configuration class annotated with @Configuration. Ensure it has a no-args constructor and fields with default values. Fields can be private; setters are not required. Ignored fields can be made final, transient, static, or annotated with @Ignore. ```java public @interface Configuration {} public @interface Ignore {} public @interface Comment { String[] value(); } public final class Example { // * To create a configuration annotate a class with @Configuration and make sure that // it has a no-args constructor. // * Now add fields to that class and assign them default values. // * That's it! Fields can be private; setters are not required. @Configuration public static class BaseConfiguration { private String host = "127.0.0.1"; private int port = 1234; // The library supports lists, sets, and maps. private Set blockedAddresses = Set.of("8.8.8.8"); // Fields can be ignored by making them final, transient, static or by // annotating them with @Ignore. private final double ignoreMe = 3.14; } // This library supports records; no @Configuration annotation required public record User( String username, @Comment("Please choose a strong password.") String password ) {} // Subclassing of configurations and nesting of configurations in other configurations // is also supported. Subclasses don't need to be annotated again. public static final class UserConfiguration extends BaseConfiguration { // You can add comments with the @Comment annotation. Each string in the comment // array is written (as a comment) on a new line. @Comment({"The admin user has full access.", "Choose a proper password!"}) User admin = new User("root", "toor"); // The User class is a record! List blockedUsers = List.of( new User("user1", null), // null values are supported new User("user2", null) ); } public static void main(String[] args) { var configFile = Paths.get("/tmp/config.yml"); var config = new UserConfiguration(); // Save an instance to the configuration file YamlConfigurations.save(configFile, UserConfiguration.class, config); // Load a new instance from the configuration file config = YamlConfigurations.load(configFile, UserConfiguration.class); System.out.println(config.admin.username); System.out.println(config.blockedUsers); // Modify the configuration and save it again config.blockedUsers.add(new User("user3", "pass3")); YamlConfigurations.save(configFile, UserConfiguration.class, config); } } ``` -------------------------------- ### YamlConfigurations Static Methods Source: https://context7.com/exlll/configlib/llms.txt Provides static methods for loading, saving, updating, reading, and writing YAML configurations. Each method has overloads for default properties, a Consumer lambda, or a fully constructed YamlConfigurationProperties object. ```APIDOC ## `YamlConfigurations` — Static Convenience Methods `YamlConfigurations` provides static `load`, `save`, `update`, `read`, and `write` methods. Each exists in three overloads: default properties, a `Consumer` lambda, or a fully constructed `YamlConfigurationProperties` object. ```java import de.exlll.configlib.YamlConfigurations; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.nio.file.Path; @Configuration class AppConfig { private String appName = "MyApp"; private int maxConnections = 100; private AppConfig() {} } Path file = Path.of("app.yml"); // update: create file with defaults if absent, otherwise load & re-save AppConfig cfg = YamlConfigurations.update(file, AppConfig.class); // load: read values from existing file (file must exist) AppConfig loaded = YamlConfigurations.load(file, AppConfig.class); // save: write instance to file (creates or overwrites) YamlConfigurations.save(file, AppConfig.class, cfg); // Inline builder customization (second overload) AppConfig custom = YamlConfigurations.update( file, AppConfig.class, builder -> builder.outputNulls(true).inputNulls(false) ); // Stream-based I/O (no file involved) var out = new ByteArrayOutputStream(); YamlConfigurations.write(out, AppConfig.class, cfg); var in = new ByteArrayInputStream(out.toByteArray()); AppConfig fromStream = YamlConfigurations.read(in, AppConfig.class); System.out.println(fromStream.appName); // MyApp ``` ``` -------------------------------- ### Post-process Configuration with Annotated Method (void return) Source: https://github.com/exlll/configlib/blob/master/README.md Use the @PostProcess annotation on a void method to directly modify the configuration instance after initialization. This method is executed but does not replace the configuration object. ```java import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PostProcess; @Configuration public final class Config { private int i = 10; private String s = "abc"; @PostProcess private void postProcess() { this.i = this.i * 2; this.s = this.s.repeat(2); } } ``` -------------------------------- ### Import ConfigLib via GitHub Packages (Gradle Groovy) Source: https://github.com/exlll/configlib/blob/master/README.md Configure your Gradle project with the GitHub Packages repository and add the ConfigLib dependency using Groovy syntax. ```groovy repositories { maven { url 'https://maven.pkg.github.com/Exlll/ConfigLib' } } dependencies { implementation 'de.exlll:configlib-yaml:4.8.1' } ``` -------------------------------- ### Import ConfigLib via GitHub Packages (Gradle Kotlin) Source: https://github.com/exlll/configlib/blob/master/README.md Configure your Gradle project with the GitHub Packages repository and add the ConfigLib dependency using Kotlin syntax. ```kotlin repositories { maven { url = uri("https://maven.pkg.github.com/Exlll/ConfigLib") } } dependencies { implementation("de.exlll:configlib-yaml:4.8.1") } ``` -------------------------------- ### Load, Save, Update YAML Configurations with Static Methods Source: https://context7.com/exlll/configlib/llms.txt Use `YamlConfigurations` static methods for simple file operations. The `update` method creates a file with defaults if it doesn't exist. Supports inline builder customization and stream-based I/O. ```java import de.exlll.configlib.YamlConfigurations; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.nio.file.Path; @Configuration class AppConfig { private String appName = "MyApp"; private int maxConnections = 100; private AppConfig() {} } Path file = Path.of("app.yml"); // update: create file with defaults if absent, otherwise load & re-save AppConfig cfg = YamlConfigurations.update(file, AppConfig.class); // load: read values from existing file (file must exist) AppConfig loaded = YamlConfigurations.load(file, AppConfig.class); // save: write instance to file (creates or overwrites) YamlConfigurations.save(file, AppConfig.class, cfg); // Inline builder customization (second overload) AppConfig custom = YamlConfigurations.update( file, AppConfig.class, builder -> builder.outputNulls(true).inputNulls(false) ); // Stream-based I/O (no file involved) var out = new ByteArrayOutputStream(); YamlConfigurations.write(out, AppConfig.class, cfg); var in = new ByteArrayInputStream(out.toByteArray()); AppConfig fromStream = YamlConfigurations.read(in, AppConfig.class); System.out.println(fromStream.appName); // MyApp ``` -------------------------------- ### Import ConfigLib via Maven Central (Gradle) Source: https://github.com/exlll/configlib/blob/master/README.md Add this dependency to your Gradle project to use ConfigLib. ```kotlin repositories { mavenCentral() } dependencies { implementation("de.exlll:configlib-yaml:4.8.1") } ``` -------------------------------- ### Customize Configuration Properties Source: https://github.com/exlll/configlib/blob/master/README.md Create a builder using YamlConfigurationProperties.newBuilder() or toBuilder() to customize storage and loading behavior. ```java YamlConfigurationProperties properties = ConfigLib.BUKKIT_DEFAULT_PROPERTIES.toBuilder() // ...further configure the builder... .build(); ``` -------------------------------- ### Supported Types in Java Source: https://github.com/exlll/configlib/blob/master/README.md Illustrates various Java types that the library supports for configuration, including primitive types, collections, and custom objects. ```java public final class SupportedTypes { boolean supported; Character supported; String supported; LocalTime supported; UUID supported; ExampleEnum supported; // where 'ExampleEnum' is some Java enum type ExampleConfig supported; // where 'ExampleConfig' is a class annotated with @Configuration ExampleRecord supported; // where 'ExampleRecord' is a Java record /* collection types */ List supported; Set supported; LocalDate[] supported; Map supported; /* nested collection types */ List> supported; int[][] supported; Map>>> supported; // supported if a custom serializer is registered java.awt.Point supported; // supported when a special properties object is used (explained further below) org.bukkit.inventory.ItemStack supported; } ``` -------------------------------- ### Configuration Class Definition Source: https://github.com/exlll/configlib/blob/master/README.md Defines a sample configuration class annotated with @Configuration. This is used to exemplify loading and saving configurations. ```java @Configuration public final class Config { /* some fields */ } ``` -------------------------------- ### Post-Processing with @PostProcess Source: https://context7.com/exlll/configlib/llms.txt Annotate a method with @PostProcess to execute it after configuration initialization. If the method returns void, it's simply called. If it returns the configuration type, the instance is replaced. ```java import de.exlll.configlib.*; import java.nio.file.Path; @Configuration class SecurityConfig { private String rawPassword = "secret"; private int sessionTimeoutSeconds = 3600; // computed at runtime, not stored private transient String hashedPassword; @PostProcess private void validate() { if (sessionTimeoutSeconds < 60) throw new IllegalStateException("Session timeout too short: " + sessionTimeoutSeconds); // derive runtime value this.hashedPassword = Integer.toHexString(rawPassword.hashCode()); } private SecurityConfig() {} } // For records, return the new instance record MathConfig(int base, int squared) { MathConfig() { this(4, 0); } @PostProcess private MathConfig compute() { return new MathConfig(base, base * base); } } MathConfig mc = YamlConfigurations.update(Path.of("math.yml"), MathConfig.class); System.out.println(mc.squared()); // 16 ``` -------------------------------- ### Define User, Participant, and Moderator Classes Source: https://github.com/exlll/configlib/wiki/Tutorial Model users with roles and moderators with emails using nested, annotated classes. Ensure default constructors are provided. ```java @Configuration public final class GameConfig { // ... enum Role {MEMBER, LEADER} @Configuration public static class User { private UUID uuid; private String name; public User(UUID uuid, String name) {/* initialize */} private User() {} } public static final class Participant extends User { private Role teamRole; public Participant(UUID uuid, String name, Role teamRole) {/* initialize */} private Participant() {} } public static final class Moderator extends User { @Comment({"The moderators email", "It must be valid!"}) private String email; public Moderator(UUID uuid, String name, String email) {/* initialize */} private Moderator() {} } } ``` -------------------------------- ### Configure and Enable ConfigLib in Bukkit Plugin Source: https://github.com/exlll/configlib/wiki/Tutorial Sets up custom YAML configuration properties, including headers, footers, and custom serializers for Bukkit plugins. This code should be placed in your main plugin class's onEnable method. ```java import de.exlll.configlib.ConfigLib; import de.exlll.configlib.NameFormatters; import de.exlll.configlib.YamlConfigurationProperties; import de.exlll.configlib.YamlConfigurations; import org.bukkit.Location; import org.bukkit.plugin.java.JavaPlugin; import java.io.File; import java.nio.file.Path; public final class GamePlugin extends JavaPlugin { @Override public void onEnable() { YamlConfigurationProperties properties = ConfigLib.BUKKIT_DEFAULT_PROPERTIES.toBuilder() .header( """ The game config for our imaginary game! Valid color codes are: &4, &c, &e """) .footer("Authors: Exlll") .addSerializer(Location.class, new GameConfig.LocationStringSerializer()) ``` -------------------------------- ### Load and Update Game Configuration Source: https://github.com/exlll/configlib/wiki/Tutorial Loads and updates a game configuration from a YAML file. Ensures the configuration is up-to-date with the latest properties. ```java .setNameFormatter(NameFormatters.UPPER_UNDERSCORE) .setFieldFilter(field -> !field.getName().startsWith("internal")) .build(); Path configFile = new File(getDataFolder(), "config.yml").toPath(); GameConfig config = YamlConfigurations.update( configFile, GameConfig.class, properties ); System.out.println(config.getWinMessage()); System.out.println(config.getLoseMessage()); System.out.println(config.getArena()); } } ``` -------------------------------- ### YamlConfigurationStore Instance Source: https://context7.com/exlll/configlib/llms.txt The `YamlConfigurationStore` class is the underlying engine for managing configurations. It is recommended for scenarios where the same configuration type is loaded or saved multiple times, as it optimizes performance by reusing the internal serializer. ```APIDOC ## `YamlConfigurationStore` — Reusable Store Instance `YamlConfigurationStore` is the underlying engine. Prefer it over the static helpers when loading or saving the same type multiple times, as it avoids re-creating the internal serializer on each call. ```java import de.exlll.configlib.YamlConfigurationProperties; import de.exlll.configlib.YamlConfigurationStore; import java.nio.file.Path; YamlConfigurationProperties props = YamlConfigurationProperties.newBuilder() .header("Server configuration — do not edit while server is running") .footer("End of config") .build(); YamlConfigurationStore store = new YamlConfigurationStore<>(ServerConfig.class, props); Path file = Path.of("plugins/MyPlugin/config.yml"); // First run: creates the file with defaults ServerConfig cfg = store.update(file); // Mutate and re-save // (assuming setters exist) store.save(cfg, file); // Later: reload from disk ServerConfig reloaded = store.load(file); System.out.println(reloaded.host); // 127.0.0.1 ``` ``` -------------------------------- ### Post-process Configuration Elements by PostProcess Key Source: https://github.com/exlll/configlib/blob/master/README.md Use ConfigurationElementFilter.byPostProcessKey to apply post-processing functions to elements annotated with @PostProcess and a specific key. The empty string key targets elements with @PostProcess but no explicit key. ```java import io.config.ConfigurationElementFilter; import io.config.ConfigurationProperties; // Assuming Config record is defined elsewhere with @PostProcess annotations // record Config( // @PostProcess(key = "double") int a, // @PostProcess(key = "double") int b, // @PostProcess(key = "tripple") int c, // @PostProcess int d, // @PostProcess(key = "missing processor") int e, // int f // ) {} ConfigurationProperties.newBuilder() .addPostProcessor( ConfigurationElementFilter.byPostProcessKey("double"), (Integer value) -> value * 2 ) .addPostProcessor( ConfigurationElementFilter.byPostProcessKey("tripple"), (Integer value) -> value * 3 ) .addPostProcessor( ConfigurationElementFilter.byPostProcessKey(""), (Integer value) -> 0 ) .build(); ``` -------------------------------- ### Define Game Configuration Structure Source: https://github.com/exlll/configlib/wiki/Tutorial Defines a configuration class with various data types, including custom objects and collections. Use @Comment for documentation and @Configuration for marking classes as configurable. ```java import de.exlll.configlib.Comment; import de.exlll.configlib.Configuration; import de.exlll.configlib.Serializer; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import java.time.LocalDate; import java.time.Month; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; @Configuration public final class GameConfig { @Comment("This message is displayed to the winner team") private String winMessage = "&4YOU WON!"; @Comment("This message is displayed to the losers") private String loseMessage = "&c...you lost!"; private ItemStack firstPrize = initFirstPrize(); private List consolationPrizes = List.of( new ItemStack(Material.STICK, 2), new ItemStack(Material.ROTTEN_FLESH, 3), new ItemStack(Material.CARROT, 4) ); private LocalDate startDate = LocalDate.of(2022, Month.JANUARY, 1); private LocalDate endDate = LocalDate.of(2022, Month.DECEMBER, 31); private Set forbiddenBlocks = Set.of(Material.LAVA, Material.BARRIER); private Moderator moderator = new Moderator(UUID.randomUUID(), "Mod", "mod@admin.com"); private Map> teams = Map.of( Permission.BLOCK_BREAK, List.of( new Participant(UUID.randomUUID(), "Alice", Role.LEADER), new Participant(UUID.randomUUID(), "Bob", Role.MEMBER) ), Permission.BLOCK_PLACE, List.of( new Participant(UUID.randomUUID(), "Eve", Role.LEADER), new Participant(UUID.randomUUID(), "Dave", Role.MEMBER) ) ); private Arena arena = new Arena(10, new Location(Bukkit.getWorld("world"), 0, 0, 0)); private int internal1 = 20; private String internal2 = "30"; private ItemStack initFirstPrize() { ItemStack stack = new ItemStack(Material.DIAMOND_AXE); stack.addEnchantment(Enchantment.DURABILITY, 3); stack.addEnchantment(Enchantment.DIG_SPEED, 5); stack.addEnchantment(Enchantment.MENDING, 1); return stack; } enum Role {MEMBER, LEADER} @Configuration public static class User { private UUID uuid; private String name; public User(UUID uuid, String name) { this.uuid = uuid; this.name = name; } private User() {} } public static final class Participant extends User { private Role teamRole; public Participant(UUID uuid, String name, Role teamRole) { super(uuid, name); this.teamRole = teamRole; } private Participant() {} } public static final class Moderator extends User { @Comment({"The moderators email", "It must be valid!"}) private String email; public Moderator(UUID uuid, String name, String email) { super(uuid, name); this.email = email; } private Moderator() {} } enum Permission {BLOCK_BREAK, BLOCK_PLACE} static final class LocationStringSerializer implements Serializer { @Override public String serialize(Location location) { String worldName = location.getWorld().getName(); int blockX = location.getBlockX(); int blockZ = location.getBlockZ(); return worldName + ";" + blockX + ";" + blockZ; } @Override public Location deserialize(String s) { String[] split = s.split(";"); World world = Bukkit.getWorld(split[0]); int x = Integer.parseInt(split[1]); int z = Integer.parseInt(split[2]); return new Location(world, x, 0, z); } } record Arena( int arenaRadius, @Comment("The world and x and z coordinates of the arena.") Location arenaCenter ) {} // GETTERS ... } ``` -------------------------------- ### Reusable YAML Configuration Store Instance Source: https://context7.com/exlll/configlib/llms.txt Employ `YamlConfigurationStore` for repeated loading/saving of the same configuration type to avoid re-initializing the serializer. Allows pre-configuration of properties like headers and footers. ```java import de.exlll.configlib.YamlConfigurationProperties; import de.exlll.configlib.YamlConfigurationStore; import java.nio.file.Path; YamlConfigurationProperties props = YamlConfigurationProperties.newBuilder() .header("Server configuration — do not edit while server is running") .footer("End of config") .build(); YamlConfigurationStore store = new YamlConfigurationStore<>(ServerConfig.class, props); Path file = Path.of("plugins/MyPlugin/config.yml"); // First run: creates the file with defaults ServerConfig cfg = store.update(file); // Mutate and re-save // (assuming setters exist) store.save(cfg, file); // Later: reload from disk ServerConfig reloaded = store.load(file); System.out.println(reloaded.host); // 127.0.0.1 ``` -------------------------------- ### Update Configuration with Record Default Values Source: https://github.com/exlll/configlib/blob/master/README.md Use the update method with Java records. A no-argument constructor provides default values if the configuration file does not exist. ```java record User(String name, String email) { User() { this("John Doe", "john@doe.com"); } } User user = YamlConfigurations.update(configurationFile, User.class); ``` -------------------------------- ### Post-process Configuration with Annotated Method (record return) Source: https://github.com/exlll/configlib/blob/master/README.md For immutable types like Java records, annotate a method that returns the record type itself. The returned instance will replace the original configuration instance. ```java import org.springframework.context.annotation.PostProcess; public record Config(int i, String s) { @PostProcess private Config postProcess() { return new Config(i * 2, s.repeat(2)); } } ``` -------------------------------- ### Configure Environment Variable Resolution Source: https://github.com/exlll/configlib/blob/master/README.md Set up environment variable overwriting by creating an EnvVarResolutionConfiguration and applying it to your ConfigurationProperties builder. Use resolveEnvVarsWithPrefix to specify a prefix for environment variables. ```java final var envVarConf = ConfigurationProperties.EnvVarResolutionConfiguration .resolveEnvVarsWithPrefix(prefix, caseSensitiveResolution); final var properties = ConfigurationProperties.newBuilder() .setEnvVarResolutionConfiguration(envVarConf) // ... build ``` -------------------------------- ### Integrate ConfigLib with Bukkit/Paper Plugins Source: https://context7.com/exlll/configlib/llms.txt Utilize `ConfigLib.BUKKIT_DEFAULT_PROPERTIES` for seamless integration with Bukkit/Paper, which includes serializers for `ConfigurationSerializable` types like `ItemStack` and `Location`. Extend these default properties using `toBuilder()` to add custom serializers, name formatters, or field filters. ```java import de.exlll.configlib.*; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.java.JavaPlugin; import java.io.File; import java.nio.file.Path; import java.util.List; @Configuration class GameConfig { @Comment("Prize awarded to the winning team") private ItemStack firstPrize = new ItemStack(Material.DIAMOND, 1); private List consolationPrizes = List.of( new ItemStack(Material.STICK, 2), new ItemStack(Material.APPLE, 3) ); private GameConfig() {} } public class MyPlugin extends JavaPlugin { @Override public void onEnable() { YamlConfigurationProperties props = ConfigLib.BUKKIT_DEFAULT_PROPERTIES.toBuilder() .header("Game configuration") .setNameFormatter(NameFormatters.UPPER_UNDERSCORE) .addSerializer(Location.class, new LocationStringSerializer()) // Assuming LocationStringSerializer is defined elsewhere .setFieldFilter(field -> !field.getName().startsWith("internal")) .build(); Path configFile = new File(getDataFolder(), "config.yml").toPath(); GameConfig config = YamlConfigurations.update(configFile, GameConfig.class, props); getLogger().info("First prize: " + config.firstPrize.getType()); } } ``` -------------------------------- ### Configure and Use YamlConfigurationProperties Source: https://github.com/exlll/configlib/wiki/Tutorial Configures YamlConfigurationProperties for saving game configurations, including Bukkit classes. This involves setting headers, footers, custom serializers, name formatters, and field filters to exclude internal fields. ```java import org.bukkit.Location; import org.configlib.ConfigLib; import org.configlib.NameFormatters; import org.configlib.YamlConfigurationProperties; import org.configlib.YamlConfigurations; import com.exlll.configlib.GameConfig; import java.io.File; import java.nio.file.Path; import org.bukkit.plugin.java.JavaPlugin; public final class GamePlugin extends JavaPlugin { @Override public void onEnable() { YamlConfigurationProperties properties = ConfigLib.BUKKIT_DEFAULT_PROPERTIES.toBuilder() .header( """ The game config for our imaginary game! Valid color codes are: &4, &c, &e "" ) .footer("Authors: Exlll") .addSerializer(Location.class, new GameConfig.LocationStringSerializer()) .setNameFormatter(NameFormatters.UPPER_UNDERSCORE) .setFieldFilter(field -> !field.getName().startsWith("internal")) .build(); Path configFile = new File(getDataFolder(), "config.yml").toPath(); GameConfig config = YamlConfigurations.update( configFile, GameConfig.class, properties ); System.out.println(config.getWinMessage()); System.out.println(config.getLoseMessage()); System.out.println(config.getArena()); } } ``` -------------------------------- ### Final Game Configuration (YAML) Source: https://github.com/exlll/configlib/wiki/Tutorial This is the complete YAML representation of the game configuration, including messages, items, dates, forbidden blocks, moderator details, and team structures. ```yaml # The game config for our imaginary game! # Valid color codes are: &4, &c, &e # This message is displayed to the winner team WIN_MESSAGE: '&4YOU WON!' # This message is displayed to the losers LOSE_MESSAGE: '&c...you lost!' FIRST_PRIZE: | ==: org.bukkit.inventory.ItemStack v: 3105 type: DIAMOND_AXE meta: ==: ItemMeta meta-type: UNSPECIFIC enchants: DIG_SPEED: 5 MENDING: 1 DURABILITY: 3 CONSOLATION_PRIZES: - | ==: org.bukkit.inventory.ItemStack v: 3105 type: STICK amount: 2 - | ==: org.bukkit.inventory.ItemStack v: 3105 type: ROTTEN_FLESH amount: 3 - | ==: org.bukkit.inventory.ItemStack v: 3105 type: CARROT amount: 4 START_DATE: 2022-01-01 END_DATE: 2022-12-31 FORBIDDEN_BLOCKS: - LAVA - BARRIER MODERATOR: UUID: 3fc1e4c3-0d6a-4342-a159-4b0fbd78cda8 NAME: Mod # The moderators email # It must be valid! EMAIL: mod@admin.com TEAMS: BLOCK_PLACE: - UUID: 5621f3b8-cbab-4571-ba97-a4ff3da59b33 NAME: Eve TEAM_ROLE: LEADER - UUID: 5b0c7fc3-2da6-48a1-bc06-1b4daa0f6881 NAME: Dave TEAM_ROLE: MEMBER BLOCK_BREAK: - UUID: a4bc6c3e-8159-431d-abde-0b19697d5505 NAME: Alice TEAM_ROLE: LEADER - UUID: e3a2fcdb-a9be-4396-ad43-32a8339220b3 NAME: Bob TEAM_ROLE: MEMBER ARENA: ARENA_RADIUS: 10 # The world and x and z coordinates of the arena. ARENA_CENTER: world;0;0 # Authors: Exlll ``` -------------------------------- ### Declaring a Configuration Class with @Configuration Source: https://context7.com/exlll/configlib/llms.txt Annotate a Java class with `@Configuration` to make it a configuration type. The class must have a no-args constructor. Fields are serialized in declaration order, with static, final, transient, and @Ignore-annotated fields being skipped. ```java import de.exlll.configlib.Comment; import de.exlll.configlib.Configuration; import de.exlll.configlib.Ignore; import java.util.List; import java.util.UUID; @Configuration public final class ServerConfig { @Comment("The address the server binds to") private String host = "127.0.0.1"; @Comment({"The listening port", "Must be between 1024 and 65535"}) private int port = 25565; // Collections of any supported type are serialized as YAML lists private List allowedIps = List.of("192.168.1.0/24", "10.0.0.0/8"); // Enums are stored by name private LogLevel logLevel = LogLevel.INFO; // final / static fields are never serialized private final String version = "1.0.0"; @Ignore private transient long runtimeStartMs; // also excluded public enum LogLevel { DEBUG, INFO, WARN, ERROR } // Private no-args constructor is fine private ServerConfig() {} } // Produces: // # The address the server binds to // host: 127.0.0.1 // # The listening port // # Must be between 1024 and 65535 // port: 25565 // allowedIps: // - 192.168.1.0/24 // - 10.0.0.0/8 // logLevel: INFO ``` -------------------------------- ### Gradle Dependency for ConfigLib (Kotlin) Source: https://context7.com/exlll/configlib/llms.txt Add ConfigLib to your project using Gradle. Includes the YAML-only artifact. ```kotlin repositories { mavenCentral() } dependencies { // Plain YAML support (no Minecraft classes) implementation("de.exlll:configlib-yaml:4.8.1") // Paper/Spigot support (includes ItemStack, Location, etc.) // implementation("de.exlll:configlib-paper:4.8.1") } ``` -------------------------------- ### Override Configuration with Environment Variables Source: https://context7.com/exlll/configlib/llms.txt Use `EnvVarResolutionConfiguration` to allow environment variables to override simple scalar configuration values. Nested paths are joined with `_`, and list elements use their zero-based index. Ensure environment variables are exported before running the application. ```java import de.exlll.configlib.*; import java.nio.file.Path; @Configuration class AppConfig { private String host = "localhost"; private int port = 8080; private AppConfig() {} } // Export before running: // MY_APP_HOST=prod.example.com // MY_APP_PORT=443 YamlConfigurationProperties props = YamlConfigurationProperties.newBuilder() .setEnvVarResolutionConfiguration( ConfigurationProperties.EnvVarResolutionConfiguration .resolveEnvVarsWithPrefix("MY_APP_", /* caseSensitive= */ false) ) .build(); AppConfig cfg = YamlConfigurations.update(Path.of("app.yml"), AppConfig.class, props); System.out.println(cfg.host); // prod.example.com (overridden by MY_APP_HOST) System.out.println(cfg.port); // 443 (overridden by MY_APP_PORT) ``` -------------------------------- ### Define Prizes with ItemStack (Java) Source: https://github.com/exlll/configlib/wiki/Tutorial Defines a primary prize using ItemStack and a list of consolation prizes. Includes a helper method to initialize the first prize with enchantments. ```java @Configuration public final class GameConfig { // ... private ItemStack firstPrize = initFirstPrize(); private List consolationPrizes = List.of( new ItemStack(Material.STICK, 2), new ItemStack(Material.ROTTEN_FLESH, 3), new ItemStack(Material.CARROT, 4) ); private ItemStack initFirstPrize() { ItemStack stack = new ItemStack(Material.DIAMOND_AXE); stack.addEnchantment(Enchantment.DURABILITY, 3); stack.addEnchantment(Enchantment.DIG_SPEED, 5); stack.addEnchantment(Enchantment.MENDING, 1); return stack; } } ``` -------------------------------- ### Subclassing Configuration Types with Inheritance Source: https://context7.com/exlll/configlib/llms.txt Configuration classes support inheritance. Fields from parent classes are serialized before child fields (top-to-bottom). The parent class must be annotated with @Configuration; subclasses inherit the annotation automatically. Ensure subclasses have a private no-argument constructor if they are to be serialized/deserialized by ConfigLib. ```java import de.exlll.configlib.*; import java.nio.file.Path; import java.util.UUID; @Configuration public abstract class BaseUser { protected UUID uuid = UUID.randomUUID(); protected String name = "anonymous"; } // Subclass does NOT need @Configuration public final class AdminUser extends BaseUser { @Comment("Admin email address") private String email = "admin@example.com"; private boolean superAdmin = false; private AdminUser() {} public AdminUser(UUID uuid, String name, String email, boolean superAdmin) { this.uuid = uuid; this.name = name; this.email = email; this.superAdmin = superAdmin; } } YamlConfigurations.save( Path.of("admin.yml"), AdminUser.class, new AdminUser(UUID.randomUUID(), "alice", "alice@example.com", true) ); // Produces (parent fields first): // uuid: 3fc1e4c3-0d6a-4342-a159-4b0fbd78cda8 // name: alice // # Admin email address // email: alice@example.com // superAdmin: true ``` -------------------------------- ### Programmatic Map Serialization with Serializers.newConfigurationTypeSerializer Source: https://context7.com/exlll/configlib/llms.txt Use this to create a standalone Serializer> for a configuration type. This is useful for embedding configuration objects inside custom storage systems or larger serializers. Ensure the configuration class is annotated with @Configuration. ```java import de.exlll.configlib.*; import java.util.Map; @Configuration class Point { private double x = 0.0; private double y = 0.0; private Point() {} Point(double x, double y) { this.x = x; this.y = y; } } ConfigurationProperties props = ConfigurationProperties.newBuilder() .setNameFormatter(NameFormatters.LOWER_UNDERSCORE) .build(); Serializer> pointSerializer = Serializers.newConfigurationTypeSerializer(Point.class, props); Map serialized = pointSerializer.serialize(new Point(3.14, 2.71)); System.out.println(serialized); // {x=3.14, y=2.71} Point deserialized = pointSerializer.deserialize(Map.of("x", 1.0, "y", 2.0)); System.out.println(deserialized.x + ", " + deserialized.y); // 1.0, 2.0 ``` -------------------------------- ### Model Teams with Participants and a Moderator Source: https://github.com/exlll/configlib/wiki/Tutorial Map permissions to lists of participants and include a moderator instance. Avoid serializing fields of a base class when a subclass is intended. ```java @Configuration public final class GameConfig { // ... private Moderator moderator = new Moderator(UUID.randomUUID(), "Mod", "mod@admin.com"); private Map> teams = Map.of( Permission.BLOCK_BREAK, List.of( new Participant(UUID.randomUUID(), "Alice", Role.LEADER), new Participant(UUID.randomUUID(), "Bob", Role.MEMBER) ), Permission.BLOCK_PLACE, List.of( new Participant(UUID.randomUUID(), "Eve", Role.LEADER), new Participant(UUID.randomUUID(), "Dave", Role.MEMBER) ) ); enum Permission {BLOCK_BREAK, BLOCK_PLACE} } ``` -------------------------------- ### Customize YAML Serialization Behavior with Builder Source: https://context7.com/exlll/configlib/llms.txt Use `YamlConfigurationProperties.newBuilder()` to customize file-level options (header, footer, charset, parent directories) and serialization behavior (name formatting, null handling, field filtering, type coercion). ```java import de.exlll.configlib.*; import java.nio.charset.StandardCharsets; YamlConfigurationProperties props = YamlConfigurationProperties.newBuilder() // File-level options .header("Auto-generated config — version 2.0\nDo not edit manually!") .footer("Generated by ConfigLib 4.8.1") .charset(StandardCharsets.UTF_8) .createParentDirectories(true) // default true // Serialization options .setNameFormatter(NameFormatters.LOWER_UNDERSCORE) // camelCase → lower_underscore .outputNulls(false) // null fields are omitted (default) .inputNulls(false) // null in file treated as missing (default) // Field filtering: exclude fields whose name starts with "internal" .setFieldFilter(field -> !field.getName().startsWith("internal")) // Allow lenient type coercion when deserializing strings .setDeserializationCoercionTypes( DeserializationCoercionType.BOOLEAN_TO_STRING, DeserializationCoercionType.NUMBER_TO_STRING ) .build(); // Re-use existing properties and override one value (Builder copy-constructor pattern) YamlConfigurationProperties propsV2 = props.toBuilder() .setNameFormatter(NameFormatters.UPPER_UNDERSCORE) // camelCase → UPPER_UNDERSCORE .build(); ``` -------------------------------- ### Maven Dependency for ConfigLib Source: https://context7.com/exlll/configlib/llms.txt Add ConfigLib to your project using Maven. Includes the YAML-only artifact. ```xml de.exlll configlib-yaml 4.8.1 ``` -------------------------------- ### Add Win and Lose Messages (Java) Source: https://github.com/exlll/configlib/wiki/Tutorial Adds string fields for win and lose messages, annotated with @Comment to provide descriptions. These fields are initialized with default values. ```java @Configuration public final class GameConfig { @Comment("This message is displayed to the winner team") private String winMessage = "&4YOU WON!"; @Comment("This message is displayed to the losers") private String loseMessage = "&c...you lost!"; } ``` -------------------------------- ### Updated Configuration File Content Source: https://github.com/exlll/configlib/blob/master/README.md The resulting YAML content of a configuration file after the 'update' method has been called, demonstrating how existing and new values are handled. ```yaml i: 20 j: 11 ``` -------------------------------- ### Define Arena using Java Record Source: https://github.com/exlll/configlib/wiki/Tutorial Model the arena with radius and center location using a Java record. Records do not require @Configuration annotation, and their components can be commented. ```java @Configuration public final class GameConfig { // ... private Arena arena = new Arena(10, new Location(Bukkit.getWorld("world"), 0, 0, 0)); record Arena( int arenaRadius, @Comment("The world and x and z coordinates of the arena.") Location arenaCenter ) {} } ```