Giter Club home page Giter Club logo

config-builder's Introduction

ConfigBuilder

A simple Java property configuration library.

Features

  • Simple API
  • Supports boolean, integer, long, float, double, string and enum entries out of the box
  • Supports custom entry types
  • Uses the simple, human-readable properties file format
  • Automatically handles saving and loading
  • Automatically corrects invalid values or missing entries
  • Supports header and per-entry comments
  • Supports default values
  • Supports min and max values
  • Zero dependencies
  • Supports Java 8 and above
  • Extensively tested with unit tests (100% code coverage)

Usage

Maven

<dependency>
  <groupId>de.maxhenkel.configbuilder</groupId>
  <artifactId>configbuilder</artifactId>
  <version>2.0.1</version>
</dependency>

<repositories>
  <repository>
    <id>henkelmax.public</id>
    <url>https://maven.maxhenkel.de/repository/public</url>
  </repository>
</repositories>

Gradle

dependencies {
  implementation 'de.maxhenkel.configbuilder:configbuilder:2.0.1'
}

repositories {
  maven {
    name = 'henkelmax.public'
    url = 'https://maven.maxhenkel.de/repository/public'
  }
}

Example Code

public static void main(String[] args) {
    Config config = ConfigBuilder.builder(Config::new)
        .path(Paths.get("config.properties")) // The path to the config file
        .keepOrder(true) // Whether the config should keep the order of the entries - Enabled by default
        .removeUnused(true) // Whether the config should remove entries that were not defined in the builder - Enabled by default
        .strict(true) // Whether the config should be strict (compliant to Javas Properties implementation) - Disabled by default
        .saveAfterBuild(true) // Whether the config should be saved after building - Enabled by default
        .build();

    System.out.println(config.booleanEntry.getKey() + ": " + config.booleanEntry.get());  // boolean: false
    System.out.println(config.integerEntry.getKey() + ": " + config.integerEntry.get());  // integer: 10
    System.out.println(config.longEntry.getKey() + ": " + config.longEntry.get());        // long: 10
    System.out.println(config.floatEntry.getKey() + ": " + config.floatEntry.get());      // float: 10.0
    System.out.println(config.doubleEntry.getKey() + ": " + config.doubleEntry.get());    // double: 10.0
    System.out.println(config.stringEntry.getKey() + ": " + config.stringEntry.get());    // string: test123
    System.out.println(config.enumEntry.getKey() + ": " + config.enumEntry.get());        // enum: TEST_1

    config.integerEntry.set(15).save(); // Set the value of the integer entry to 15 and saves the config asynchronously
    config.integerEntry.set(12).saveSync(); // Set the value of the integer entry to 12 and saves the config synchronously
    config.integerEntry.reset().save(); // Reset the value of the integer entry to the default value and saves the config asynchronously
}

public class Config {
    public final ConfigEntry<Boolean> booleanEntry;
    public final ConfigEntry<Integer> integerEntry;
    public final ConfigEntry<Long> longEntry;
    public final ConfigEntry<Float> floatEntry;
    public final ConfigEntry<Double> doubleEntry;
    public final ConfigEntry<String> stringEntry;
    public final ConfigEntry<TestEnum> enumEntry;

    public Config(ConfigBuilder builder) {
        builder.header(
                "My config version 1.0.0",
                "This is a test config"
        );
        booleanEntry = builder.booleanEntry("boolean", false).comment("This is a boolean entry");
        integerEntry = builder.integerEntry("integer", 10, 0, 20).comment("This is an integer entry with the range 0-20");
        longEntry = builder.longEntry("long", 10L, 0L, 20L).comment("This is a long entry with the range 0-20");
        floatEntry = builder.floatEntry("float", 10F, 0F, 20F).comment("This is a float entry with the range 0.0-20.0");
        doubleEntry = builder.doubleEntry("double", 10D, 0D, 20D).comment("This is a double entry with the range 0.0-20.0");
        stringEntry = builder.stringEntry("string", "test123").comment("This is a string entry");
        enumEntry = builder.enumEntry("enum", TestEnum.TEST_1).comment("This is an enum entry");
    }
}

public enum TestEnum {
    TEST_1, TEST_2, TEST_3;
}

Generated config file:

# My config version 1.0.0
# This is a test config

# This is a boolean entry
boolean=false
# This is an integer entry with the range 0-20
integer=10
# This is a long entry with the range 0-20
long=10
# This is a float entry with the range 0.0-20.0
float=10.0
# This is a double entry with the range 0.0-20.0
double=10.0
# This is a string entry
string=test123
# This is an enum entry
enum=TEST_1

Supported Value Types

Besides the types shown in the above example, there are several built-in types that are supported out of the box.

UUIDs

public class Config {
    public final ConfigEntry<UUID> uuidEntry;
    public Config(ConfigBuilder builder) {
        uuidEntry = builder.entry("uuid_entry", UUID.fromString("cee9f733-870b-48e3-936f-d3be5d527524")).comment("This is a UUID entry");
    }
}

Lists

The StringList type is a wrapper around an immutable list. It is serialized as a comma separated list of strings.

It can be instantiated with StringList.of(String...) or StringList.of(List<String>).

public class Config {
    public final ConfigEntry<StringList> stringListEntry;
    public Config(ConfigBuilder builder) {
        stringListEntry = builder.entry("string_list_entry", StringList.of("test", "test1", "test2")).comment("This is a string list entry");
    }
}

The same can be done with IntegerList.

Maps

The StringMap type is a wrapper around an immutable map.

It can be instantiated with StringMap.of(List<Map<String, String>) or StringMap.builder().put(key, value).putAll(map).build().

public class Config {
    public final ConfigEntry<StringMap> stringMapEntry;
    public Config(ConfigBuilder builder) {
        stringMapEntry = builder.entry("string_map_entry", StringMap.builder().put("test", "123").put("test1", "456").build()).comment("This is a string map entry");
    }
}

Adding Custom Value Types

Variant 1

Add your value serializer while creating your config builder. You can also override the default value serializer for an already existing type by adding a new value serializer for that type. Custom types should always be immutable.

public static void main(String[] args) {
    ConfigBuilder
            .builder(Config::new)
            .addValueSerializer(CustomType.class, CustomTypeValueSerializer.INSTANCE)
            .build();
}

public class Config {
    public final ConfigEntry<CustomType> customType;

    public Config(ConfigBuilder builder) {
        customType = builder.entry("test", new CustomType("Test")).comment("This is a custom entry");
    }
}

public class CustomType {
    private final String value;

    public CustomType(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

public class CustomTypeValueSerializer implements ValueSerializer<CustomType> {
    public static final CustomTypeValueSerializer INSTANCE = new CustomTypeValueSerializer();

    @Nullable
    @Override
    public CustomType deserialize(String str) {
        return new CustomType(str);
    }

    @Nullable
    @Override
    public String serialize(CustomType val) {
        return val.getValue();
    }
}

Variant 2

Annotate your custom type with @ValueSerializable and provide a serializer class that implements ValueSerializer. Custom types should always be immutable.

@ValueSerializable(CustomTypeValueSerializer.class)
public class CustomType {
    private final String value;

    public CustomType(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

Your serializer class should have a no-args constructor and implement ValueSerializer. Invalid conversions should return null.

public class CustomTypeValueSerializer implements ValueSerializer<CustomType> {
    @Nullable
    @Override
    public CustomType deserialize(String str) {
        return new CustomType(str);
    }
    
    @Nullable
    @Override
    public String serialize(CustomType val) {
        return val.getValue();
    }
}

Custom types can be used like this:

public static void main(String[] args) {
    Config config = ConfigBuilder.builder(Config::new)
            .path(Paths.get("config.properties"))
            .build();

    System.out.println(config.customType.get().getValue()); // Prints "Test"
    config.customType.set(new CustomType("Test2"));
    System.out.println(config.customType.get().getValue()); // Prints "Test2"
}

public class Config {
    public final ConfigEntry<CustomType> customType;

    public Config(ConfigBuilder builder) {
        customType = builder.entry("test", new CustomType("Test")).comment("This is a custom entry");
    }
}

config-builder's People

Contributors

henkelmax avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.